[Thread] Semantics regarding memory barrier/happens-before relationship
|const| |int| |BUF_SIZE = 10;| |const| |int| |ITERS = 100;|
|boost::mutex io_mutex;|
|class| |buffer| |{| |public||:| | ||typedef| |boost::mutex::scoped_lock| | ||scoped_lock; ||| |[..]|
| ||int| |get()| | ||{| | ||scoped_lock lk(mutex);| | ||if| |(full == 0)| | ||{| |[..]| | ||while| |(full == 0)| | ||cond.wait(lk);| | ||}| | ||int| |i = buf[c];| | ||c = (c+1) % BUF_SIZE;| | ||--full;| | ||cond.notify_one();| | ||return| |i;| | ||}| | | |private||:| | ||boost::mutex mutex;| | ||boost::condition cond;| | ||unsigned ||int| |p, c, full;| | ||int| |buf[BUF_SIZE];| |};| I wonder if it is possible the compiler produces optimised code and checking the member 'full' before creating the scoped lock. Imagine two
Hi, I have read an article on Dr.Dobbs (http://drdobbs.com/cpp/184401518?pgno=3) about the Boost Thread Library and a given example quoted below raised a question to me regarding race condition safety (stripped). threads calling/entering method buffer.get. That would lead to a possible race condition. Why is this not possible and how is this guaranteed with current C++ Compilers? Thanks for any reply, Falk Sticken
On 11/8/11, Falk S.
Hi,
I have read an article on Dr.Dobbs (http://drdobbs.com/cpp/184401518?pgno=3) about the Boost Thread Library and a given example quoted below raised a question to me regarding race condition safety (stripped).
|const| |int| |BUF_SIZE = 10;| |const| |int| |ITERS = 100;|
|boost::mutex io_mutex;|
|class| |buffer| |{| |public||:| | ||typedef| |boost::mutex::scoped_lock| | ||scoped_lock; ||| |[..]|
| ||int| |get()| | ||{| | ||scoped_lock lk(mutex);| | ||if| |(full == 0)| | ||{|
I wonder if it is possible the compiler produces optimised code and checking the member 'full' before creating the scoped lock. Imagine two threads calling/entering method buffer.get. That would lead to a possible race condition. Why is this not possible and how is this guaranteed with current C++ Compilers?
Technically there is no guarantee, but it always works. It works because either: - the compiler recognizes the underlying OS level calls (or compiler level intrinsics) inside the inlined constructor of scoped_lock() and knows not to optimize around them - the compiler sees a library call (either the constructor or the a library call from the inlined constructor) and says "I have no idea what that library call does, I better not optimize around it" typically the second. Tony
participants (2)
-
Falk S.
-
Gottlob Frege