Skip to main content
GameDev.net gamedev.net
🔒 Locked

volatile bool vs event

Started by quant May 27, 2006 at 8:43 AM 17 replies 2.9k views
Original Post
quant
quant
Are there any advantages to using an unnamed win32 event (CreateEvent) over using a volatile bool?
-keyboard
C0D1F1ED
C0D1F1ED
Yes, when waiting for an event the O.S. will pause the thread and continue another thread (possibly another application), or put the processor in an energy-saving halting state when there are no more tasks. With a volatile bool you could end up with a situation where the processor 'spins' so it takes valuable execution time until another thread gets scheduled.

Only for very short spin times a volatile bool can be more efficient because events do have an overhead.
outRider
outRider
Just remember, you can't guarantee synchronization with a volatile bool unless you use the CMPXCHG instruction.
quant
quant
I was thinking more along the line of

if(waitforsingleobject(Event, 0))
{
//do something
}


Compared with

if(myeventbool)
{
//do something
}

Are you saying it is safer to use an event over using a bool?
-keyboard
taby
taby
It is emperically safer to use an atomic API event. Like mentioned above, the CPU could very well be stolen by the OS halfway through a bool assignment. Not a super big problem since it only really relies on one bit.. until you think that there's 8 of them, and the last bit may be the only one that doesn't get filled before the CPU moves on to another thread.

All Win32 events are guaranteed to be atomic. Either it grants threads a little bit of extra CPU time to get the job done, or it simply blocks all threads waiting for that event and by-passes them continually until the initial thread finishes the "atomic" setting of the event. Either way, it's guaranteed by MS that it works, I can't see how Windows could be so stable if it didn't. ;)
janta
janta
reminds me of Wrinting unmaintainable code
Quote:

Use Spin Locks
Avoid actual synchronization primitives in favor of a variety of spin locks -- repeatedly sleep then test a (non-volatile) global variable until it meets your criterion. Spin locks are much easier to use and more "general" and "flexible " than the system objects.


This is just an entertaining quotation ;)
quant
quant
Is writing to a bool not an atomic operation?
-keyboard
Shannon Barber
Shannon Barber
Quote:
Original post by quant
Is writing to a bool not an atomic operation?


There are x86 instuctions to make it atomic, but I doubt the compiler would use them by default.
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Enigma
Enigma
Writing to a bool will be atomic. It's test-and-set which usually isn't.

Σnigma
Catafriggm
Catafriggm
Individual writes and reads are always atomic given that:
- They are entirely contained in one cache line (if your compiler pads structures to align variables, this should be guaranteed)
- They are not larger than the maximum size the processor can write in a single instruction (generally the processor word size)

As one person pointed out, you must use atomic primitives to atomically read a value, modify it, then write it back.
taby
taby
Quote:
Original post by Enigma
Writing to a bool will be atomic. It's test-and-set which usually isn't.

Σnigma


That makes a lot of sense. I never saw it that way before.
chollida1
chollida1
Quote:
Original post by taby
It is emperically safer to use an atomic API event. Like mentioned above, the CPU could very well be stolen by the OS halfway through a bool assignment. Not a super big problem since it only really relies on one bit.. until you think that there's 8 of them, and the last bit may be the only one that doesn't get filled before the CPU moves on to another thread.


It was my understanding that a bool will be writen in one atomic operation.

Cheers
Chris
CheersChris
Catafriggm
Catafriggm
Quote:
Original post by chollida1
It was my understanding that a bool will be writen in one atomic operation.


Depending on the size of a bool, it always will. I know in VC++ a bool is 1 byte, meaning that no matter where it is, it will always satisfy both of the conditions I mentioned, and thus always be read/written atomically.
outRider
outRider
Reading or writing is atomic. Reading and writing isn't (unless the CPU in question has an atomic test-and-set and you make use of it), which is what you need if you want synchronization. Based on the original poster's pseudo code, he either doesn't need synchronization, or (more likely) the pseudo code doesn't accurately represent what he's trying to do. Chances are somewhere along the line the thread/process waiting on the flag will have to reset it to indicate that it responded to the event, at which point you'll run into problems.
quant
quant
The real code is something more like

//shared memoryvolatile bool should_exit = false;volatile bool should_do_something = false;volatile bool done_something = false;//thread 1while(!should_exit){  if(should_do_something)  {    should_do_something = false;    do_something();    done_something = true;  }  else  {     Sleep(0);  }}//thread 2should_do_something = true;while(!done_something){  Sleep(0);}done_something = false;


The code in thread 1 is only called by that thread, and the shared variables are only shared between thread 1 and thread 2. You can view thread 2 as a sort of commander, telling thread 1 when to run and when to sleep. As I see it, the alternative is

//shared eventsHANDLE should_exit;HANDLE should_do_something;HANDLE done_something;//thread 1while(!WaitForSingleObject(should_exit, 0)){  WaitForSingleObject(should_do_something, INFINITE);  do_something();  SetEvent(done_something);}//thread 2SetEvent(should_do_something);WaitForSingleObject(done_something, INFINITE);


The second looks more pleasing to me, but I am worried that I am using a sledge hammer to do something that I could do with my thumb. The code assumes that the event is automatically reset when an object "aquires" the event.
-keyboard
quant
quant
//shared memoryvolatile bool should_exit = false;volatile bool should_do_something = false;volatile bool done_something = false;void WaitForVolatileBool(volatile bool& mybool){  while(!mybool)  {     Sleep(0);  }  mybool = false;}//thread 1while(!should_exit){  WaitForVolatileBool(should_do_something);  do_something();  done_something = true;}//thread 2should_do_something = true;WaitForVolatileBool(done_something);


The first example could be refactored slightly to the above code. WaitForVolatileBool would be a lite version of WaitForSingleObject. Technically WaitForVolatileBool is not threadsafe if two threads are waiting on the same variable at the same time, but in the above code only one thread can be waiting on the variable at any time. That seems quite subtle to me, but it would be more efficient (yes I know what premature optimization is, but the code will be used a lot).
-keyboard
C0D1F1ED
C0D1F1ED
In my experience, Sleep(0) can still hog the processor. When there's no other thread to execute it quickly returns to the same thread. So it's almost equivalent to a spin loop. Unfortunately, Sleep(1) already puts it to bed for a whole millisecond (an eternity in computer land). Unless you wake it up sooner. But then you have to use events as far as I know...
quant
quant
I am not too concerned about it churning up the processor as you describe, the main concern is transferring execution from the commander thread (thread 2) to the worker thread (thread 1) in the quickest time possible (and visa versa when the worker has finished its execution).
-keyboard
outRider
outRider
Your version with two flags works as long as you only have one master thread and one slave thread. Don't introduce any more threads and you should be fine, otherwise you'll have to use an algorithm that makes stronger guarantees.

Good luck.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.