[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Linux sound (and threads)

Pierre Phaneuf wrote:

> Well, if it works correctly now, it should be fine, but I think that in
> the long run, out of process could be a bad idea, particularly in the
> area of games like Quake2, where gamers complain that a single machine
> gets 34 fps in Windows and only 33.2 in Linux... ;-)

Well, the sound code is such that it can be embedded in-process or
migrated out. Should the need arise I can cut-and-paste the code out of
xhsound and into a module which is called on every frame refresh.

> With only two threads in such a manner, you could only use a mutex for
> an queue with move events coming from the input thread, so that's not
> too bad as far as "complicated" goes. But is the render thread looking
> often at the queue? If so, it has the lock often, and the input thread
> has to wait. Or if the input thread got the lock, the render thread goes
> dead in the mean time... This is taking it a bit simply though. I guess
> you could "try" to get the lock for a few milliseconds, then, seeing
> that you can't have it now, go and render some stuff. But now it is
> getting more complicated...

Well, the render thread simply does, "move, render, sleep for 20ms,
repeat". Win32 has a critical section mechanism that's optimized for two
or more threads in the same process, and faster than mutexes (mutices?)
in this case. The render thread would take the critical section, move
and render the sprites, and then relinquish it when it was done. The
event thread would only try to take the critical section when it wanted
to change some property of a sprite while the render thread was
rendering. (I say "take" and "relinquish" because like mutices,
semaphores, and the famous Perl "patch pumpkin" Win32 critical sections
are objects which are passed around, the possession of which guarantees
you exclusive use of the resources it governs.)

The Win32 function EnterCriticalSection() would attempt to take the
critical section, and busy-wait until it was available. The render
thread got a higher priority than the event thread, so it would hang
onto the critical section a bit more often. When it slept, the event
thread would jump in and do its thing. It was a pretty simple
multithreading example, but a tad on the slow side. Eventually I plan on
migrating Sprite32 back onto the Win32 side of things, making it a bit
more portable so games could be compiled for Linux and Win32 without
code changes. If I had to do it all over again, everything would go back
into that single thread.

*sigh* I miss Win32. IMHO 'Doze 95 and NT are bad implementations of
some pretty good ideas. But hey, at least Wine rules :)

> What this means is that you have a scheduler object with a bunch of
> "thread" objects. The thread objects have a virtual method called
> "step", which does a "bit" of work. This is the "small unit of
> execution". The explicit dispatching is that each "thread" decides of
> when to do the context switch themselves, when their step() method
> return. Then, the scheduler object calls the next "thread" object step()
> method, and it goes around that way. The threads have a "die" property
> that they can set before returning from their step() method to tell the
> schedule they are to be removed from the list.
> The trouble with this method is that to get a "multiple thread running
> at once" effect, you have to keep the processing in the step() method at
> a minimum. For a small thing, like a fade thread, this is simple, you
> just rotate the color map then return, but for anything more
> complicated, you have to cut the task in small parts, keep context
> between step() calls and so on. This:

You should have no problems understanding how to program for Sprite32,
then :) All of the Sprite objects are stored in a linked list. The Run()
method of SpriteAppWin then iterates down the list, first calling the
virtual MoveSprite() method of every sprite, and then RenderSprite()
which is virtual but is nine times out of ten the same for each sprite.
It's quite fast, even when you have a lot of things on the screen at
once. MoveSprite can become pretty hairy when there's a lot of state
involved that you wish to keep track of. But you can create lots of cool
effects by coding each sprite's methods as if they were independent
little programs instead of wondering, "Now where am I in the loop and
what do I have to do here". (I know that Gnudius has a lot of cheap,
two-dollar effects such as the stippled fade-in-and-out background
effect, but still...)

> Hmm... QuickThreads, eh? Sure that I'll take a look at this! But I
> wouldn't wager this library being under a looser license than the
> LGPL...

The copyright is actually very loose and is BSDish, like the Wine
license. Guile itself is GPLed; QuickThreads is a separate package
altogether that's just bundled in because it was used to implement
threading in Guile. From the traffic that's going on in the Guile ML,
they really want to rewrite Guile threading to use kernel-level threads,
if available. So get QuickThreads free in specially marked boxes of
Guile, while supplies last. :)

Jeff Read <bitwize@geocities.com>
Unix Code Artist, Anime Fan, Really Cool Guy