#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono_literals;
condition_variable cv;
mutex mu;
void thread1()
{
mu.lock();
unique_lock lck(mu);
cv.wait(lck);
cout << 1;
}
void thread2()
{
this_thread::sleep_for(1s);
mu.lock();
cv.notify_all();
cout << 2;
}
int main()
{
thread t1(thread1);
thread t2(thread2);
this_thread::sleep_for(2s);
}
This code was expected to show number 1
and 2
, but shows nothing.
If a condition variable has waited with a mutex, then the mutex is unlocked, right?
Several issues with the code:
thread2 is locking the mutex, but not unlocking it.
thread1 is locking it twice. Once with the explicit mu.lock and again with the unique_lock constructor. This is undefined behavior - usually an automatic deadlock so the developer knows they have coded it incorrectly. The constructor of unique_lock that only takes a mutex as a parameter will automatically call mu.lock for you. And the destructor will call mu.unlock.
condition variables need some sort of "condition" to check to guard against spurious wakeup. In other words, when thread 1 wakes up, it can't assume that thread 2 was the one that woke it up. It's not a good pattern to assume so. So while having the mutex locked, the code needs to check for "has the thing I'm waiting for actually happened". And if not, then it needs to go back to waiting. I've updated your code below to simulate thread 2 setting a global variable and having thread 1 wait for it to change.
No need to sleep(2) in main. Just wait for both threads to be done to decide it's ok to exit main.
Closer to what you want:
condition_variable cv;
mutex mu;
bool has_value_been_set = false;
int value = 0;
void thread1()
{
unique_lock<mutex>lck(mu);
while (has_value_been_set == false)
{
cv.wait(lck);
}
cout << "thread1: the value set by the other thread is: " << value << "\n";
}
void thread2()
{
sleep(1);
{
unique_lock<mutex>lck(mu);
value = 42;
has_value_been_set = true;
cout << "thread2: setting the value: " << value << "\n";
}
cout << "thread2: notifying other threads: " << value << "\n";
cv.notify_all();
}
int main()
{
thread t1(thread1);
thread t2(thread2);
// wait for both threads to be done
t1.join();
t2.join();
}