There are very few reasons to create another thread for something, and
more often I see thread abuse than use. It might be tempting (whizzy/cool)
to use a thread, but there are so few circumstances when it’s actually
needed that when someone says they need a thread for something, more often
than not they don’t!
May be I should have explained the situation in which I intended to use
SDL_ThreadIsRunning () a bit more.
The code below shows the relevant parts of my event loop (which is run in
the main thread).
ready = SDL_FALSE;
while (!ready) {
// redraw all areas that have been invalidated
if (gView) gView->Update ();
// perform all tasks
SFTaskManager::GlobalTaskManager ().DoTasks ();
// handle network events
SFTCPClientManager::GlobalTCPClientManager ().DoTCPClients ();
// poll events and handle them
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_QUIT: /* Quit now */
ready = SDL_TRUE;
break;
case SDL_KEYUP:
SFKeyboardHandlerManager::GlobalKeyboardHandlerManager ().HandleKeyUp
(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode);
break;
case SDL_MOUSEBUTTONUP:
if (gView) {
gView->HandleMouseMove (*gView, event.button.x, event.button.y);
gView->HandleMouseUp (*gView, event.button.button);
}
break;
case …:
break;
}
}
}
The thread that I want to know the status of, is started somewhere deep in
the HandleMouseUp call and is calculating a chess move. That takes some
time. In the mean time I want the GUI to stay responsive. Eg. one of the
tasks registered to the GlobalTaskManager updates a chess clock on the
screen and I don’t want that clock to pause while the move is being
calculated. In another one of the tasks registered to the GlobalTaskManager
I want to check whether the chess thread has finished so I can perform the
move.
Latency is not an issue at all. Besides I don’t see a reason why latency
would be large unless the GUI is very busy.
Of course there are ways to do this without a thread. I could split up the
move calculation in small pieces and call those pieces from a task. I could
also make a copy of my event loop and call that copy every now and then from
the chess code. In both cases the chess code would be a lot more complicated
and dependent on this particular GUI.
int StartCalculateThread(void )
{
uint i;
for(i=0; i<1000000; i++)
{
/ Calculate Stuff /
}
/ I’m about to exit: tell the world! */
IsCalculateThreadAboutToExit = true;
}
void LaunchCalculateThread()
{
IsCalculateThreadAboutToExit = false;
SDL_CreateThread(StartCalculateThread);
}
bool IsThreadStillRunning()
{
return (!IsCalculateThreadAboutToExit);
}
Ok, let us assume some imaginary OS and hardware where:
- a bool is stored as 4 bytes.
- true is stored as 0xffffffff, false is stored as 0x00000000
- !IsCalculateThreadAboutToExit is compiled as IsCalculateThreadAboutToExit
== 0
- hardware stores 2 bytes at a time (may be only in special cases where the
4 bytes are in two different pages)
Now with a dying thread I risk that I get a context switch after the first
half of IsCalculateThreadAboutToExit has been set. So inthe main thread
IsThreadStillRunning () will return true.
So in some imaginary app, I might immediately, that is in the same timeslice
start a new thread. After another context switch the dying thread would be
setting the other half of IsCalculateThreadAboutToExit and I would assume
that the other thread would have finished as well.
May be this guaranteed to never happen but I prefer not to think about these
issues and rely on an API call that someone smarter than me has written and
that many smart people have reviewed.
Also, don’t forget to declare it volatile.
That is a good point, but probably not very important in my case because I
would check it only once each event loop deep down in
SFTaskManager::GlobalTaskManager ().DoTasks ();, so I am confident that my
compiler will not be able to optimize the check away.
However the very fact that you have to think about such subtleties made me
ask whether I overlooked some SDL API call.
Huib-Jan