Jump to content


Multithreading / WaitForSingleObject


7 replies to this topic

#1 Wernaeh

    Senior Member

  • Members
  • PipPipPipPip
  • 368 posts

Posted 15 October 2005 - 08:07 PM

Hiho there =)

Just a few small questions today that I came up with when working on a
multithreaded worker / overseer implementation =)

I have a situation where in a windows environment one thread first rises a
flag indicating a second thread should terminate. Then, the first thread calls
Resume() on the second thread - just in case it might be suspended - and
then calls WaitForSingleObject(secondthread). The second thread runs in a
loop, and is testing for the exit flag in each cycle.

i.e. in pseudocode



// The second thread's main loop

void ThreadLoop

{


    while (true)

    {


        // Lock all data used by this thread

        SetMutex();


        // See if we should terminate.

        // If so, fall out of the thread loop

        if (bExitFlag)

        {

             ReleaseMutex();

             return;

        }


        // Otherwise, do our working stuff, and then

        // release the mutex again.

        DoSomeStuff();

        ReleaseMutex();


        // Finally, start sleeping so we won't cost any cycles

        Suspend();

   }

}


// The first thread's function to terminate the second thread

void TerminateOtherThread()

{

    // Set the exit flag for the other thread

    SetMutex();

    bExitFlag = true;

    FreeMutex();


   // Now, revive the other thread in case it is suspended,

   // and then, wait for its termination

   ResumeThread(secondthread);

   WaitForSingleObject(secondthread);


   // Release remaining thread API stuff

   CloseHandle(secondthread);

}



So now, on to the questions that popped into my mind.

May this setup lead to a deadlock ? - I think so.

Why ? Because ResumeThread() may be called before the second thread is
actually suspended, thus doing nothing, then the second thread Suspends(),
and finally the first thread waits for a suspended second thread, so thats a
no-no. Any workaround solution - except perhaps putting a mutex around the
suspending command ?

Second, is WaitForSingleObject terminating when the specified process _is_
terminated, or when it has _been_ terminated ? The MSDN is a little unclear
about this. So if my second thread ends before my first thread actually
reached the WaitForSingleObject() call, will WaitForSingleObject return as it
should?

The entire setup represents a rendering thread within a larger physics
simulation. Is suspending the rendering thread even a good idea
performancewise if we are aiming at 30 frames or so per second ?

And finally, do I need to set a mutex if I just change a single boolean
variable ? I guess I needn't, since the variable set operation should be
atomar anyways.

I'm not too experienced in this whole multithreaded business, so I'd be glad
about any input. =)

Thank you for you help and time,
Cheers,
- Wernaeh

#2 MJeannig

    Member

  • Members
  • PipPip
  • 29 posts

Posted 16 October 2005 - 10:03 AM

This is not very good pratice to communicate with your thread using variables. I'm not sure about what does your FreeMutex, so I may be wrong. One better way is to use an controlled loop with UserAPC (user asynchronous proc ). These are function called in the target thread context while it is in alertable state (SleepEx, WaitForSingleObject, ... )

MyThread()

{

    while(WaitForSingleObject(exitEvent) == WAIT_IO_COMPLETION);

}


MyProc()

{

//Do something in MyThread context

}


MyApp()

{

    QueueUserAPC(hMyThread,MyProc); // run some code in MyThread context

    SetEvent(exitEvent);                     // tell the thread to close

}

Or you may keep a mutex/event solution with a two event solution using waitformultipleobject:
MyThread()

{

    do

    {

        ... // Do something

        HANDLE handles[] = {exitEvent,continueEvent}

        r = WaitForMultipleObject(handles)

    }while(r == 1+WAIT_OBJECT_0); // 1 is index of continueEvent

}

MyApp()

{

    SetEvent(continueEvent); // Make it continue

    SetEvent(exitEvent);       // Make it stop

}



MJ

#3 MJeannig

    Member

  • Members
  • PipPip
  • 29 posts

Posted 16 October 2005 - 10:16 AM

Wernaeh said:

The entire setup represents a rendering thread within a larger physics
simulation. Is suspending the rendering thread even a good idea
performancewise if we are aiming at 30 frames or so per second ?
Its better to not use thread if you can (except may be for multiprocessor optimization purpose ). Thread are for accessing hardware, or deal with long operations that could deteriorate user experience. Suspending the rendering thread is probably not a good idea. Do you have separate threads for physic and rendering ?

Wernaeh said:

And finally, do I need to set a mutex if I just change a single boolean
variable ? I guess I needn't, since the variable set operation should be
atomar anyways.
Its a dangerous field to try to guess what is atomic and what isnt. It will probably work 99.9999% of the time and it would be a hard debugging time if it cause crash. You will never know if your engine is really stable.

#4 corey

    Member

  • Members
  • PipPip
  • 78 posts

Posted 16 October 2005 - 05:34 PM

If you're really worried about it and must suspend the thread instead of sleeping for a period of time then code with that in mind.

Instead of calling a direct suspend, setup an event object and wait for that to be signaled. Here, you could use wait for multiple objects and check for either resume event or close event.

Use a mutex for any synchronization. Windows does provide some atomic manipulation functions if you're interesting. We're using them in G3D's new AtomicInt32 and GThread classes. http://msdn.microsof...kedexchange.asp

corey

#5 Wernaeh

    Senior Member

  • Members
  • PipPipPipPip
  • 368 posts

Posted 26 October 2005 - 09:03 PM

Hi there again =)


Sorry for the response lag, I had a lot to do the past two weeks with the new university semester starting, and such =)

First, thank you all for your helpful posts =)
Now, just a few comments, and answers to questions.


@MJeannig

Quote

I'm not sure about what does your FreeMutex

SetMutex() and FreeMutex() are just wrappers for OS specific calls that either occupy or release a mutex object (or a critical section object, in my case)

I didn't completely understand APCs though I read the msn about it. It would certainly be nice if you could detail a bit on their application and such =)
However, I think your event-based approach is a very good solution to my problem, indeed. I will try it out right after this post.

Quote

Its a dangerous field to try to guess what is atomic and what isnt.It will probably work 99.9999% of the time

Yes that's exactly what I was worried about ;)


@corey

Quote

Do you have separate threads for physic and rendering ?

Yes I do. I have got a fixed timestep logic thread (also doing all physics) and the rendering thread. I also have plans for another loader thread running in the background.

There are good alternatives to threading, I know. One example would be to just break off rendering after either a fixed amount of objects rendered, or after a finite time passed (i.e. its time for the logic again). Then, do a logic step without rendering, and continue rendering on the previous frame where you left.
This is a bit tedious since you need to explicitly code time checks all over your rendering code, and you need to somehow store where you left rendering. Additionally, this approach requires two different versions of each object - the one manipulated by logics, and the one rendered, to avoid scene inconsistencies. However, the latter also is a necessity for threaded rendering, if you don't want to mutex each and every single object.

Another alternative would be to just have the logic catch up with rendering. This means, render a frame, then see how many logic frames should have passed, and process these. Then render once more. I don't fancy this approach though, since it gives very inresponsive logics (i.e. wenn the rendering of a frame kicks in, you basically lose input for some time, and then get very fast input for repeating the logic steps).

This also explains the reason for using a threaded approach. Apart from running faster on multicore CPUs, the basic coding is much simpler and reliable, once you have a proper synching system in place.


Anyways, I had some time to do some work on my threading stuff the past few hours (... boring economy lecture courses ...) . I think I finally came up with a solution which just uses mutexes. It is ugly as hell though, and I'm pretty much too embarrassed to post it here ;)

For anybody out there trying something similiar, either don't suspend your worker thread, or use events, as suggested by the poster above, it gets much, much easier that way.

Thank you all again for your answers.

Cheers,
- Wernaeh

#6 corey

    Member

  • Members
  • PipPip
  • 78 posts

Posted 26 October 2005 - 09:16 PM

Wernaeh,

I would probably still suggest my approach for a clean solution and readability.

If you do post, we can try to help iron out some clarity or other issues if you like.

Corey

#7 Wernaeh

    Senior Member

  • Members
  • PipPipPipPip
  • 368 posts

Posted 26 October 2005 - 09:22 PM

As I said, I will try out the event-based approach right now ;) as it can probably never be as ugly as the one I devised, with using critical sections ans synch variables all over ;)

#8 corey

    Member

  • Members
  • PipPip
  • 78 posts

Posted 27 October 2005 - 12:54 AM

Wernaeh said:

As I said, I will try out the event-based approach right now ;) as it can probably never be as ugly as the one I devised, with using critical sections ans synch variables all over ;)
Well, it might not be a problem for you, but if you're supporting any windows version below NT, there is no tryLock() for critical sections! That is usually an easy way to simulate events -- but then again you wanted to suspend the thread.

corey





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users