FastEvents question (for Bob or anyone who knows)

The notes on FastEvents say that only the thread that initialized SDL should be used to call FE_PollEvent() or FE_WaitEvent(). I’m curious as to why that is, since it seems to me to be completely backwards for a multithreaded game.

The main thread has to be used for rendering. As I understand it, this is an invariant. The main thread MUST be your rendering thread. Problem with doing event handling on the same thread is that it’s conceivable for certain commands to use blocking behavior. (My game engine, which I’m trying to port to SDL does this in fact. There are a handful of keyboard commands that call Sleep() as part of their handler.) Doing this on the rendering thread is a bad idea for obvious reasons.

Is there a particular reason why the FastEvents reading functions should only happen on the main thread, and is there a modification that could be made to work around the restriction?

Mason

I’m sure Bob could explain more about the technical specifics, but I’ll just mention that you can use FastEvents ‘reading’ functions from another thread if (like you said) SDL and FastEvents are initialized in that thread. There is no reason why you need to initialize SDL or FastEvents in the main thread. Therefore, the flow goes something like this:

MAIN: Detach a thread.
THREAD1: Call SDL_Init and FE_Init.
THREAD1: Enter event loop, calling FE_PollEvent or FE_WaitEvent.
MAIN: Setup rendering context; enter rendering loop.

The only thing to watch out for is to make sure the main thread does not call SDL functions until the detached thread has initialized SDL, but this is fairly obvious and very simple.

That’s it,
chaz----- Original Message -----
From: Mason Wheeler
To: A list for developers using the SDL library. (includes SDL-announce)
Sent: Monday, May 05, 2008 10:18 AM
Subject: [SDL] FastEvents question (for Bob or anyone who knows)

The notes on FastEvents say that only the thread that initialized SDL should be used to call FE_PollEvent() or FE_WaitEvent(). I’m curious as to why that is, since it seems to me to be completely backwards for a multithreaded game.

The main thread has to be used for rendering. As I understand it, this is an invariant. The main thread MUST be your rendering thread. Problem with doing event handling on the same thread is that it’s conceivable for certain commands to use blocking behavior. (My game engine, which I’m trying to port to SDL does this in fact. There are a handful of keyboard commands that call Sleep() as part of their handler.) Doing this on the rendering thread is a bad idea for obvious reasons.

Is there a particular reason why the FastEvents reading functions should only happen on the main thread, and is there a modification that could be made to work around the restriction?

Mason



SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

MAIN: Detach a thread.
THREAD1: Call SDL_Init and FE_Init.
THREAD1: Enter event loop, calling FE_PollEvent or
FE_WaitEvent.
MAIN: Setup rendering context; enter rendering
loop.

So the thread you setup SDL in doesn’t have to be the one you do your rendering in? That might work, then…

----- Original Message -----
From: onefriedrice@brokenzipper.com (Charles McGarvey)
To: A list for developers using the SDL library. (includes SDL-announce)
Sent: Monday, May 5, 2008 10:34:27 AM
Subject: Re: [SDL] FastEvents question (for Bob or anyone who knows)

The notes on FastEvents say that only the thread that initialized SDL
should be used to call FE_PollEvent() or FE_WaitEvent(). I’m curious as to
why that is, since it seems to me to be completely backwards for a
multithreaded game.

Well, what seems backward to you is not backward to others :-). The reason
that FE functions must be called in the same thread that initialized SDL is
because they use SDL event handling functions and those functions must be
called from the main SDL thread. The SDL functions have that limitation
because of limitations of the OSes that SDL supports.

The main thread has to be used for rendering. As I understand it, this is
an invariant. The main thread MUST be your rendering thread.

Not true in general but true enough.

Problem with doing event handling on the same thread is that it’s
conceivable for certain commands to use blocking behavior.

Can you give me and example? I don’t think I have ever seen a command that
showed blocking behavior that was a problem.

(My game engine, which I’m trying to port to SDL does this in fact. There
are a handful of keyboard commands that call Sleep() as part of their
handler.) Doing this on the rendering thread is a bad idea for obvious
reasons.

So don’t do it on the rendering thread. Do it in a separate thread. BTW, why
do they call Sleep()? Using any kind of delay call in a threaded program is
usually (not always) a sign of a poor design. Generally the result of not
understanding how threads really work.

Is there a particular reason why the FastEvents reading functions should
only happen on the main thread,

Yes, as stated above, they call SDL functions that can only be called on the
main thread. OTOH, you can send an FE from any thread.

and is there a modification that could be made to work around the
restriction?

No.

Bob PendletonOn Mon, May 5, 2008 at 11:18 AM, Mason Wheeler wrote:

Mason


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

(My game engine, which I’m trying to port to SDL does this in fact. There are a handful of keyboard
commands that call Sleep() as part of their handler.) Doing this on the rendering thread is a bad idea
for obvious reasons.

So don’t do it on the rendering thread. Do it in a separate thread. BTW, why do they call Sleep()? Using
any kind of delay call in a threaded program is usually (not always) a sign of a poor design. Generally
the result of not understanding how threads really work.
I’m aware of the pitfalls. But it’s the simplest way to do things if you’ve got good timing routines to make sure thread-switching delays don’t throw your timing off, or if you need to delay for a period that can be measured in seconds, not fractions-of-seconds.

For example, when the user hits the “menu” key, the screen fades out, then a menu fades in. This is implemented on the event handling thread like this:

Change game engine state to “fading”.
Assign game engine’s fade time to 1200 ms and begin fadeout. (Handled by rendering thread.)
Sleep(1500).
Set menu engine’s state to active and draw menu to render target.
Assign game engine’s fade time to 1200 ms and begin fadein.
Sleep(1500)
Change game engine state to “in_menu” and resume normal operation.

(My game engine, which I’m trying to port to SDL does this in fact.
There are a handful of keyboard

commands that call Sleep() as part of their handler.) Doing this on the
rendering thread is a bad idea

for obvious reasons.

So don’t do it on the rendering thread. Do it in a separate thread. BTW,
why do they call Sleep()? Using
any kind of delay call in a threaded program is usually (not always) a
sign of a poor design. Generally
the result of not understanding how threads really work.
I’m aware of the pitfalls. But it’s the simplest way to do things if you’ve
got good timing routines to make sure thread-switching delays don’t throw
your timing off, or if you need to delay for a period that can be measured
in seconds, not fractions-of-seconds.

For example, when the user hits the “menu” key, the screen fades out, then
a menu fades in. This is implemented on the event handling thread like
this:

Change game engine state to “fading”.
Assign game engine’s fade time to 1200 ms and begin fadeout. (Handled by
rendering thread.)
Sleep(1500).
Set menu engine’s state to active and draw menu to render target.
Assign game engine’s fade time to 1200 ms and begin fadein.
Sleep(1500)
Change game engine state to “in_menu” and resume normal operation.

Well, if you really want to do it that way then the pseudo code above should
be run in a separate thread. You have the event handler start it and let it
handle things for you. My experience is that that won’t actually work
because there is no way to force the thread to execute, but this is a valid
use of sleep() in a thread.

Another problem with your approach to the problem is that the process takes
2.7 seconds to bring the menu up. During that time the customer may have
asked for a different menu so you need to be able to abort the whole thing.

I would do it a very different way. I would have an ordered queue (heap) of
future actions events that the rendering engine looks at to decide what to
do next. For complex interactions I would have a set of state machines that
are used to move the interactions along.

So my event handler would be rather different. In the following pseudo code
t is the current time. When the customer asks for a menu to pop up my
handler would push the following action events on the heap.

@ t+0 send “set fade out time” 1200 to rendering engine
@ t+0 send “begin fade out” to rendering engine
@ t+1200 send “Finish fade out” to rendering engine
@ t+1200 send “pop up menu” to menu engine

Now, I am assuming that the rendering engine is trying to keep a nice
animation going on the screen even while it is fading out. The “t+x” above
is the time the event should be delivered to the rendering engine. The
variable “t” is the current time. At the beginning of each frame the
rendering engine looks to see if there are any pending actions events whose
times are in the past or are to happen right now. So, the first two events
will be processed at the beginning of the next frame. The second two events
will be processed 1200 ms in the future. The rest of the interaction will be
initiated by the menu engine at some time in the future. No further
interaction with the input event handler is needed. Other interactions can
over lap with the ones already in the action queue.

Since the action queue is implemented as a heap inserting items is O(log n)
and removing items is O(n) so it is very efficient.

The result is a system that is very simple and very efficient and does not
require threads for very light weight interactions. You can save threads for
places where you can really make effective use of them.

The easy way to implement this is to have the action queue sorted by time
and have only pointers (or references depending on your choice of language)
to a closure that invokes a method of a class that implements a state
machine. That way the code that processes actions just invokes the closure
method for all pending actions whose action time is <= now.

The really nice thing about this approach is that you can (usually) run all
the pending actions in parallel and make nice use of a bunch of processors.

You can find lots off information on this approach in any book on discrete
event simulation.

Bob PendletonOn Tue, May 6, 2008 at 9:04 AM, Mason Wheeler wrote:


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Another problem with your approach to the problem is that the process takes 2.7 seconds to bring
the menu up. During that time the customer may have asked for a different menu so you need to be
able to abort the whole thing.
[Big long menu explanation]

Wrong sort of menus. Think of what happens when you hit the “menu” button on a Final Fantasy game. Same basic idea here. When you call for the menu, nothing else can (or should!) happen until the menu has appeared. You have some good ideas, though. I’ll probably end up using some of them in other places. Thanks!

----- Original Message -----
From: bob@pendleton.com (Bob Pendleton)
To: A list for developers using the SDL library. (includes SDL-announce)
Sent: Tuesday, May 6, 2008 12:53:44 PM
Subject: Re: [SDL] FastEvents question (for Bob or anyone who knows)

For example, when the user hits the “menu” key, the screen fades out, then a menu fades in.
This is implemented on the event handling thread like this:

Change game engine state to “fading”.
Assign game engine’s fade time to 1200 ms and begin fadeout. (Handled by rendering thread.)
Sleep(1500).
Set menu engine’s state to active and draw menu to render target.
Assign game engine’s fade time to 1200 ms and begin fadein.
Sleep(1500)
Change game engine state to “in_menu” and resume normal operation.

Uh, don’t most people use state machines for that? Quadra has a
hierarchical state machine, where you can just put in “processes” for
fading in and out of things, where it doesn’t call you “some random
time after the fade in is done”, but calls you the instant it’s done.

It seems that not that long ago, everything was single-threaded,
because the games were for DOS, and there was just no other option
(not even a sound thread!). Now there’s multi-threading, but I’m not
entirely sure it’s a better thing. :-)On Tue, May 6, 2008 at 10:04 AM, Mason Wheeler wrote:


http://pphaneuf.livejournal.com/

Uh, don’t most people use state machines for that? Quadra has a
hierarchical state machine, where you can just put in “processes” for
fading in and out of things, where it doesn’t call you “some random
time after the fade in is done”, but calls you the instant it’s done.

In case you need an awful one to inspire you into making a decent one
(if the awful one is nice, how amazing would a decent one be!?):

http://code.google.com/p/quadra/source/browse/trunk/quadra/skelton/include/overmind.hOn Tue, May 6, 2008 at 5:26 PM, Pierre Phaneuf <@Pierre_Phaneuf> wrote:


http://pphaneuf.livejournal.com/

For example, when the user hits the “menu” key, the screen fades out,
then a menu fades in.
This is implemented on the event handling thread like this:

Change game engine state to “fading”.
Assign game engine’s fade time to 1200 ms and begin fadeout. (Handled by
rendering thread.)
Sleep(1500).
Set menu engine’s state to active and draw menu to render target.
Assign game engine’s fade time to 1200 ms and begin fadein.
Sleep(1500)
Change game engine state to “in_menu” and resume normal operation.

Uh, don’t most people use state machines for that?

Yes, indeed the do. But, a lot of programmers these days have never heard of
a state machine.

Quadra has a
hierarchical state machine, where you can just put in “processes” for
fading in and out of things, where it doesn’t call you “some random
time after the fade in is done”, but calls you the instant it’s done.

It seems that not that long ago, everything was single-threaded,
because the games were for DOS, and there was just no other option
(not even a sound thread!). Now there’s multi-threading, but I’m not
entirely sure it’s a better thing. :slight_smile:

Well, DOS has been dead as a game platform for at least 10 years. Doing
multi-threading on DOS was actually pretty simple. Oddly enough, it usually
worked more the way people expected it to than it does on modern operating
systems. :slight_smile:

Bob PendletonOn Tue, May 6, 2008 at 4:26 PM, Pierre Phaneuf wrote:

On Tue, May 6, 2008 at 10:04 AM, Mason Wheeler wrote:


http://pphaneuf.livejournal.com/


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Yes, indeed the do. But, a lot of programmers these days have never heard of
a state machine.

A crying shame. Since that’s how computer works, I find it pretty
essential, myself. :slight_smile:

Well, DOS has been dead as a game platform for at least 10 years. Doing
multi-threading on DOS was actually pretty simple. Oddly enough, it usually
worked more the way people expected it to than it does on modern operating
systems. :slight_smile:

Well, I know it’s been dead, but people haven’t all noticed (see
http://pphaneuf.livejournal.com/172824.html). I’m not sure that it
worked very differently, but it’s more that people who did
multi-threading on DOS had to know the hardware inside-out, so their
expectations were set with a much better understanding of what really
happened.

Nowadays, people “just run it in a thread”, so when reality catches up
to them, there’s often much more sparks, possibly nice big explosions,
it’s quite pretty. :wink:

But my main point is that most of the concurrency in games is between
blitting and game logic (and not so much inside of game logic), so
most games would be content have a single thread and an video API that
lets the video card do the work asynchronously (might not be
somentirely the case of SDL, due to the focus on simplicity). I
suppose faking it with a thread for doing the synchronous blitting
(your “video card” thread, if you will) and another for everything
else is sensible, but not knowing state machines will definitely put a
damper on one’s career as a video game developer, for sure. :-)On Wed, May 7, 2008 at 12:40 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

Yes, indeed the do. But, a lot of programmers these days have never heard
of a state machine.

Sad, but true.

Well, DOS has been dead as a game platform for at least 10 years. Doing
multi-threading on DOS was actually pretty simple.

Multi-tasking on DOS was simple. More often than not, multi-threading on DOS
was nothing more than cooperative multi-tasking. Many years ago I wrote a
pre-emptive multi-tasking system on DOS for a company, complete with 'aging’
of processes so that low priority processes never got locked out. Even though
it wasn’t difficult, there were few instances in my career in which I had
more fun.

Oddly enough, it usually
worked more the way people expected it to than it does on modern operating
systems. :slight_smile:

I don’t think that’s odd. With DOS, you had complete control of the system;
that doesn’t happen with any decent modern operating system (which IMO,
doesn’t include Windows).

(Note for the younger folks who may not know: To age a process, you increase
its priority every time it’s eligible to run but isn’t selected to run. When
it does run, you set the process priority back to its default value.)

JeffOn Wed May 7 2008 09:40, Bob Pendleton wrote:

Yes, indeed the do. But, a lot of programmers these days have never heard
of a state machine.

Sad, but true.

Yep, I occasionally teach a game programming class. Most of the people who
take the class have degrees. EE majors all know state machines in side an
out. Some CS majors have heard of state machines, but only those who have
taken a course on theory of computation really know them, and they usually
don’t realize that they have practical applications.

Once people see how easy many problems are when looked at as state machines
they usually get pretty excited about them.

Well, DOS has been dead as a game platform for at least 10 years. Doing
multi-threading on DOS was actually pretty simple.

Multi-tasking on DOS was simple. More often than not, multi-threading on
DOS
was nothing more than cooperative multi-tasking. Many years ago I wrote a
pre-emptive multi-tasking system on DOS for a company, complete with
’aging’
of processes so that low priority processes never got locked out. Even
though
it wasn’t difficult, there were few instances in my career in which I had
more fun.

Yeah, me too. I had a nice cooperative threading package written using
setjmp() and longjmp(). I also wrote a preemptive thread package that
required me to reprogram the timer interrupt. Which is not the big deal
people think it is. All the old DOS C compilers had built in functions to
work with I/O ports and to write interrupt routines. And, dozens of books
had all the code you needed laid out for you. Adding threading was no big
deal.

The result was a true preemptive threading package where every thread was
guaranteed to run. Unlike modern thread packages where you can’t count on a
thread running unless you can make sure that all other threads block.

Oddly enough, it usually
worked more the way people expected it to than it does on modern
operating
systems. :slight_smile:

I don’t think that’s odd. With DOS, you had complete control of the system;
that doesn’t happen with any decent modern operating system (which IMO,
doesn’t include Windows).

(Note for the younger folks who may not know: To age a process, you
increase
its priority every time it’s eligible to run but isn’t selected to run.
When
it does run, you set the process priority back to its default value.)

I just always used round robin. I guess I was lazy…

Bob PendletonOn Wed, May 7, 2008 at 10:36 PM, Jeff <j_post at pacbell.net> wrote:

On Wed May 7 2008 09:40, Bob Pendleton wrote:

Jeff


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Round robin is perfectly fine if all your processes have the same priority.
IIRC, our system had three or four categories of processes. Something like

  1. Processes with hard deadlines (the definition of real-time).
  2. Those that really, really need to be processed soon.
  3. Things we’ll get around to when we darned well feel like it.
  4. Some we don’t much care about, but they’ve gotta run sometime.

JeffOn Mon May 12 2008 06:46, Bob Pendleton wrote:

(Note for the younger folks who may not know: To age a process, you
increase
its priority every time it’s eligible to run but isn’t selected to run.
When
it does run, you set the process priority back to its default value.)

I just always used round robin. I guess I was lazy…