I reviewed the implementation of VC ++ std::condition_variable(lock,pred) , basically, it looks like this:
template<class _Predicate> void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { // wait for signal and test predicate while (!_Pred()) wait(_Lck); }
Basically, a bare wait calls _Cnd_waitX , which calls _Cnd_wait , which calls do_wait , which calls cond->_get_cv()->wait(cs); (they are all in the cond.c file).
cond->_get_cv() returns Concurrency::details::stl_condition_variable_interface .
If we go to the primitives.h file, we will see that under windows 7 and above we have the stl_condition_variable_win7 class, which contains the good old win32 CONDITION_VARIABLE and wait calls __crtSleepConditionVariableSRW .
When doing a little debugging of the assembly, __crtSleepConditionVariableSRW just extract the pointer to the SleepConditionVariableSRW function and name it.
Here's what: as far as I know, win32 CONDITION_VARIABLE not a kernel object, but a user object. Therefore, if any thread notifies this variable and the thread does not actually sleep on it, you have lost the notification, and the thread will remain asleep until it reaches the timeout, or some other thread will notify about it. A small program can prove this - if you skip the alert point, your thread will stay awake, although some other thread has notified it.
My question is this:
one thread expects a condition variable, and the predicate returns false. Then comes the whole chain of calls described above. During this time, another thread changed the environment, so the predicate will return true and notify the condition variable. We passed the predicate in the source stream, but we still did not get into SleepConditionVariableSRW - the call chain is very long.
So, although we notify the condition variable and a predicate placed in the condition variable will definitely return true (since the notifier did this), we still block the condition variable, possibly forever.
How should this behave? A big ugly race condition seems to be waiting. If you notify the condition variable, and the predicate returns true, the stream must be unlocked. But if we are in the uncertainty between predicate checking and sleep, we are locked forever. std::condition_variable::wait not an atomic function.
What does the standard say about this, and is it really a race condition?