Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Empty while loop not checking condition

In a multithreaded C++ program, I have the equivalent of this running in one thread:

while(obj->member) { } // waiting for obj->member to be set to false in another thread

and in another thread, obj->member is set to false. Even when it's set to false, however, the loop doesn't break. If I change it to this:

while(obj->member) { Sleep(1) }

It works as expected and breaks when obj->member is set to false in the other thread.
Why does it work like this?

like image 991
Hock Avatar asked Aug 17 '10 18:08

Hock


3 Answers

Try making member volatile. This will force it to be fetched from memory each time it is used, rather than from a CPU register (which is how the compiler might optimise it.)

like image 140
Mark H Avatar answered Oct 06 '22 06:10

Mark H


Obj must be declared volatile. That tells the compiler that it's value may change by some other thread.

When you add the Sleep, the compiler knows other threads are at work, and assumes that it might change.

like image 45
James Curran Avatar answered Oct 06 '22 06:10

James Curran


The fact that it works is mostly accidental. If you want to do things like this dependably, you just about need to use some sort of OS-supplied IPC mechanism, possibly with Boost Interprocess (e.g., mutex or semaphore) to give a more portable front end.

volatile, while often put forward as a solution to problems like this, is neither necessary nor sufficient. It can hurt performance (a lot) but still isn't enough to make threading work correctly. If you're programing for .NET, Microsoft has defined its version of volatile to provide (at least some degree of) thread safety. Otherwise (in real C or C++), it's of little real use, and can cause considerable harm.

I should also mention that this is a long ways from the first time this mistake has been made. Way back when, no less an authority than Andre Alexandrescu wrote a fairly substantial article in Doctor Dobbs about using volatile for threading. He's since realized that he was wrong, but (to a large extent) the damage was done -- especially since volatile is oh so very close to doing the right things that it's extremely easy to mistake it for being right/useful in threading.

like image 37
Jerry Coffin Avatar answered Oct 06 '22 08:10

Jerry Coffin