Hello, there is an abstract task: three asynchronous threads are created, the first - the manager - waits 3 seconds, then uses the condition variable to start outputting two threads waiting for a signal:

namespace mutexes { std::mutex m; std::condition_variable cond; std::atomic<bool> at = ATOMIC_VAR_INIT(0); void thread_1() { while(true) { static int i = 0; std::cout<<"thread 1\n"; std::this_thread::sleep_for (std::chrono::seconds(1)); if(i==5) break; if(i++==2) { at = 1; cond.notify_all(); } } at = 0; } void thread_2() { while(true) { std::unique_lock<std::mutex> lk(m); cond.wait(lk,[]{ return at == 1;}); std::cout<<"thread 2\n"; std::this_thread::sleep_for (std::chrono::milliseconds(500)); } } void thread_3() { while(true) { std::unique_lock<std::mutex> lk(m); cond.wait(lk,[]{ return at == 1;}); std::cout<<"thread 3\n"; std::this_thread::sleep_for (std::chrono::milliseconds(500)); } } } //namespace mutexes int main() { //запускаем все три потока асинхронно std::thread([]{ std::thread thrd1(&mutexes::thread_1); std::thread thrd2(&mutexes::thread_2); std::thread thrd3(&mutexes::thread_3); thrd1.detach(); thrd2.detach(); thrd3.detach(); std::this_thread::sleep_for (std::chrono::seconds(6)); }).join(); } 

as a result, the output goes only from the second (thread_2) ... I cannot understand why, apparently the dead lock of the mutex ... help to make the output to the console go from both threads

    2 answers 2

    The problem with your source code is that both threads require a lock on the same mutex to work — so only one can work at a time. Why should "this one" not be a stream number 2 every time? Absolutely correct behavior.

    You probably should, after receiving the task, release the lock so that the threads can work simultaneously:

     void thread_2() { while(true) { { std::unique_lock<std::mutex> lk(m); cond.wait(lk,[]{ return at == 1;}); } std::cout<<"thread 2\n"; std::this_thread::sleep_for (std::chrono::milliseconds(500)); } } 

    PS Why threads 2 and 3 can not be started immediately, but by thread 1 after the timeout expires? That would simplify everything.

    • hmm, if you do it by your method, then you will only have to notify 2 and 3 streams once, but I need them to wait depending on the managed stream - then they work ... well, let's say, some kind of web server: all the time should expect there inside the cycle everything should be going on, and not a cycle separately ... maybe there are some patterns how to implement it correctly? but after the waiting time has elapsed, it is impossible to start threads this is a completely different task, and I need to launch it, then "suspend", as it were, and then launch it again - xperious
    • one
      @xperious rewrote to wait every time. But the analogy with the web server is a curve - other mechanisms are used there (usually each worker thread just waits on a socket). - Pavel Mayorov
    • @xperious I can advise you to read about the synchronization primitive "turn" and about the standard task "supplier-consumer" (producer-consumer) - Pavel Mayorov
    • Honestly, it did not work out in your corrected way so that it works from one mutex (although it is strange, in theory, it should work) ... only from two different ones. but thanks for the idea ... but not, it seems, everything is right, thanks for the answer - xperious

    I answer my own question ... the output from two streams is just this:

     namespace mutexes { std::mutex m1; std::mutex m2; std::condition_variable_any cond; std::atomic<bool> at = ATOMIC_VAR_INIT(0); void thread_1() { while(true) { static int i = 0; std::cout<<"thread 1\n"; std::this_thread::sleep_for (std::chrono::seconds(1)); if(i==5) break; if(i++==2) { at = 1; cond.notify_all(); } } at = 0; } void thread_2() { std::unique_lock<std::mutex> lk(m1); while(true) { cond.wait(lk,[]{ return at == 1;}); std::cout<<"thread 2\n"; std::this_thread::sleep_for (std::chrono::milliseconds(500)); } } void thread_3() { std::unique_lock<std::mutex> lk(m2); while(true) { cond.wait(lk,[]{ return at == 1;}); std::cout<<"thread 3\n"; std::this_thread::sleep_for (std::chrono::milliseconds(500)); } } } //namespace mutexes int main() { //запускаем все три потока асинхронно std::thread([]{ std::thread thrd1(&mutexes::thread_1); std::thread thrd2(&mutexes::thread_2); std::thread thrd3(&mutexes::thread_3); thrd1.detach(); thrd2.detach(); thrd3.detach(); std::this_thread::sleep_for (std::chrono::seconds(6)); }).join(); } 

    platform linux_x86_64 ... would be glad if someone would explain why it works only with std :: condition_variable_any and not with std :: condition_variable

    • I don’t know how multithreading (different types of cond) is implemented in crosses, but I suspect that pthreads are the basis (in Linux). Read man pthread_cond_signal (other man pthread _... also worth reading) and pay attention to the section Rationale Multiple Awakenings by Condition Signal . Apparently the appropriate algorithm is implemented only for the type std::condition_variable_any - avp
    • one
      Actually, I'm not sure that the code in the answer is correct, because you use 2 different mutex (m1 and m2) with the same variable cond. And thread1 calls notify without capturing any of these mutex. In man pthread_cond_signal write - " if predictable scheduling behavior is required, then you can pthread_cond_broadcast () or pthread_cond_signal (). " - avp
    • Thanks for the answer - xperious