#include <iostream>
#include <chrono>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::atomic<int> ready( 0 );
void worker_thread1()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk( m );
cv.wait( lk, [] { return ( ready==1 ); } ); // waits for ready to become 1
// after the wait, we own the lock.
std::cout << "Worker thread 1 started\n";
ready = 2; // so 2nd thread continues
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_all for details)
lk.unlock();
cv.notify_all();
}
void worker_thread2()
{
std::unique_lock<std::mutex> lk( m );
cv.wait( lk, [] { return ( ready==2 ); } ); // waits for ready to become 2
std::cout << "Worker thread 2 started\n";
ready = 3;
lk.unlock();
cv.notify_all();
}
int main()
{
std::thread worker1( worker_thread1 );
std::thread worker2( worker_thread2 );
// send data to the worker thread
{
//std::lock_guard<std::mutex> lk( m ); // <<-- required by C++ standard
ready = 1;
std::cout << "main() signals data ready for processing\n";
}
//cv.notify_one(); // since only 1 worker is notified, program may deadlock if worker 2 is chosen
cv.notify_all();
// wait for the workers
{
std::unique_lock<std::mutex> lk( m );
cv.wait( lk, [] { return ( ready==3 ); } );
}
std::cout << "Back in main()\n";
worker1.join();
worker2.join();
}