0

I have been trying condition_variable::wait and precisely I am using :

 template< class Predicate >
 void wait( std::unique_lock<std::mutex>& lock, Predicate pred );

but I am a little bit confused when I executed it. This the simple example:

 std::condition_variable cv;
 std::mutex cv_m;
 bool flag = false;

 void waits()
 {
   std::unique_lock<std::mutex> lk(cv_m);
   std::cerr << "Waiting... \n";

   cv.wait(lk,[]() {return flag == true;});
   std::cerr << "...finished waiting " << flag << std::endl;
 }

 void signals()
 {
    //std::this_thread::sleep_for(std::chrono::seconds(1));

   std::unique_lock<std::mutex> lk(cv_m);
   std::cout <<"Counting...."<< std::endl;
   flag = true;
     for(int i = 0; i < 5; i++) {
       std::cout << i << std::endl;
   }

  cv.notify_all();

 }

 int main()
 {
   std::thread t1(waits), t2(waits), t3(waits), t4(signals);
   t1.join();
   t2.join();
   t3.join();
   t4.join();

   return 0;
 }

if I am delay the signals() with

  std::this_thread::sleep_for(std::chrono::seconds(1));

it works as expected while if I put the above line under comment the output it is a mess. Shouldnd the wait condition put on hold the execution of waits() anyway ? Why do I need a delay the output changes every time and most of the time messed up ?

An example of the output

 Waiting... 
 Counting....
 0
 1
 2
 3
 4
 Waiting... 
 ...finished waiting 1
 Waiting... 
 ...finished waiting 1
 ...finished waiting 1

Thank you for any help

3
  • mixed up. Example of the output Waiting... Counting.... 0 1 2 3 4 Waiting... ...finished waiting 1 Waiting... ...finished waiting 1 ...finished waiting 1 Commented Oct 9, 2014 at 15:12
  • Do note that the ostreams (cout, cerr) are shared resources as well, which also have to be synchronized. Commented Oct 9, 2014 at 15:22
  • @Jamboree The standard streams by default are safe (as in, not causing UB) to access concurrently (but could produce interleaved characters without additional synchronization). Commented Oct 9, 2014 at 15:25

1 Answer 1

1

You have a race condition. It is possible for t4 to grab the mutex and run to completion before the other threads have a chance to get into the wait. Thus they miss the signal.

You need to synchronize so that the t1, t2, and t3 get into the wait before t4 starts. Anytime a sleep seems to fix a problem in threaded code, you probably have a race condition that requires real synchronization to fix properly.

Sign up to request clarification or add additional context in comments.

5 Comments

So why the condition_variable if I have race condition anyway ?
Sorry, I don't understand what you are asking.
I have seen example using condition_variables to notify one or more thread that something has changed, therefore I supposed that notify-wait were a way to syncronize threads. If I need to delay to make them synconized why do I need to use condition variable ?
A condition variable is a way to synchronize threads, although it may not work as you expect. In particular, only threads that are waiting on the condition variable when notifyAll() is called will be signalled. Threads that enter the wait after the notifyAll() call will wait for another signal. Therefore if your t4 completes before all the other threads have entered the wait, some of them will be waiting for another signal (that never comes), thus your code deadlocks. To fix your example you need to make sure t1,t2 and t3 enter the wait before t4 can grab the mutex.
@dohashi If pred() is true when wait(lock, pred) is called, it doesn't actually wait at all and so won't deadlock.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.