考察以下代码:
#include <iostream>
#include <condition_variable>
#include <thread>
std::mutex mutex_;
std::condition_variable condVar;
bool dataReady{false};
void WaitingForWork()
{
std::cout << "Waiting" << std::endl;
std::unique_lock<std::mutex> lk(mutex_);
condVar.wait(lk, []{return dataReady;});
std::cout << "Running" << std::endl;
}
void SetDataReady()
{
{
std::unique_lock<std::mutex> lk(mutex_);
dataReady = true;
}
std::cout << "Data prepared" << std::endl;
condVar.notify_one();
}
int main()
{
std::thread t1(WaitingForWork);
std::thread t2(SetDataReady);
t1.join();
t2.join();
return 0;
}
输出的打印出现以下情况:
hank@hank-ThinkPad-T450s:~/cpp$ ./test_cv
Waiting
Running
Data prepared
按照一般的理解,等待线程t1中的“Running”打印应该在t2线程执行完notify_one函数之后才能执行,即t2线程的“Data prepared”应该是在"Running"之前打印。
解释:
虽然代码中t1要比t2先创建,但是由于操作系统调度的原因,有可能t2线程执行到22行的时候,t1线程才开始执行到13行,此时mutex锁和dataReady变量都是满足条件的,即条件变量的wait函数立刻返回,所以就出现了"Running"打印先于“Data prepared”打印,后面的notify_one函数其实也没啥作用了(但是不能不写,因为有可能t1线程真的在13行阻塞住了,只有靠t2线程执行notify_one函数解救它了)。
可以在28行和29行之间加入一个睡眠10ms语句,就会发现每次“Running”打印都是出现在"Data prepared"打印之后了。