Sharing scripts for condition_variable

A condition variable can be used to signal other threads, something happened:

mutex m; condition_variable cv; thread t1([&cv]{ // processing ... cv.notify_one(); }); ... unique_lock<std::mutex> lck(m); cv.wait(lck); 

But, as you see, there is a window of opportunity that the processing of the stream is completed and the notification passes by before we wait to be notified, so we will always wait.

In this case, a common solution is to use the flag:

 mutex m; condition_variable cv; bool done = false; thread t1([&cv,&done]{ // processing ... done = true; cv.notify_one(); }); ... unique_lock<std::mutex> lck(m); cv.wait(lck, [&done]{return done;}); 

Does the flag use the general way of using condition_variable , or is my interpretation incorrect?

+4
source share
2 answers

A condition variable should always be associated with some condition that you should check:

  unique_lock <mutex> lck (m);
     while (! something ) 
       cv.wait (lck); 

The condition is checked while holding the mutex, therefore it is implied that the mutex must protect the data associated with the condition, so you know that it will not change between testing and waiting.

The while test is not just an if , because some implementations of variable conditions (including those based on pthreads) may wake up falsely, i.e. when no one has signaled this, so you should check the condition in a loop and repeat, wait until it is. There wait overload, which takes a predicate and automatically processes false awakenings, waiting for the predicate to return true, for example. here the above example is modified to use a lambda that checks the condition:

  unique_lock <mutex> lck (m);
     cv.wait (lck, [&] {return something ;}); 

(In simple cases, I found that an explicit while easier to read.)

The condition variable used can be thought of as a 3-tuple consisting of a condition variable, a mutex and a predicate, which are conceptually related to each other, using together to wait for the condition variable. All parallel expectations for an object of a variable of a certain condition must use the same mutex and, as a rule, also expect the same predicate (or related predicate, which depends on the same data protected by the same mutex.)

+8
source

Typically, the condition_variable variables are used in scenarios where one thread detects that it cannot act and decides to wait until a condition is met (in the English sense). condition_variable itself is not the main mechanism for notifying that a thread should continue, but rather, if any thread is waiting, it should double-check, as the state could change, and now it can be good.

One of the simplest examples is the queue of manufacturers / consumers, where the consumer will have the following code:

 void consume() { empty.wait( [&] { return !queue.empty(); } ); // extract data from the queue and consume it here } 

That is, the stream does not just wait for the variable condition_variable , but rather waits until the state of the object is such that the stream can continue. Likewise, the condition_variable notification does not indicate the continuation of another thread, just notifying any thread that is waiting for the condition to be re-tested, as the state could have changed.

Returning to your use case, if the condition that must be met to continue the thread is that the other thread is done , then using this flag is fine.

+1
source

Source: https://habr.com/ru/post/1416475/


All Articles