首先根据: The C++ core guideline 的第 42 条中提到:不要在没有条件的情况下等待( Don’t wait without a condition).主要是为了解决:
- 唤醒丢失
- 虚假唤醒
下面是范例代码:
#include <condition_variable>
#include <iostream>
#include <thread>
std::mutex mutex_;
std::condition_variable condVar;
bool dataReady{false};
void waitingForWork(){
std::cout << "Waiting " << std::endl;
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, []{ return dataReady; }); // (4)
std::cout << "Running " << std::endl;
}
void setDataReady(){
{
std::lock_guard<std::mutex> lck(mutex_);
dataReady = true;
}
std::cout << "Data prepared" << std::endl;
condVar.notify_one(); // (3)
}
int main(){
std::cout << std::endl;
std::thread t1(waitingForWork); // (1)
std::thread t2(setDataReady); // (2)
t1.join();
t2.join();
std::cout << std::endl;
}
这里再贴一下搜到的资料里 condition_variable 的处理逻辑:
wait (lck, pred); 其实等价于 while (!pred()) wait(lck);,它的运行机制如下:
- 线程获取 mutex 的锁,然后对 predicate 的结果进行检查: true:线程继续往下执行; false:condVar.wait() 解锁 mutex,然后线程进入等待(阻塞)状态。
- 假如 condVar 已经在等待状态,此时得到通知(不管发送线程发送,还是虚假唤醒): 线程进入非阻塞状态,然后重新获取 mutex 的锁。 线程检查 predicate 的结果: true:线程继续往下执行; false:condVar.wait() 解锁 mutex,然后线程进入等待(阻塞)状态。
这里我的问题是: 假设运行步骤是这样:
- t2 线程(setDataReady)先执行了。这个时候
dataReady = true. 并且notify_one了。 - t1 线程(waitingForWork)里 wait 的 predicate 为 true.直接往下执行了。并不会阻塞在 condVar.wait 的阶段(根据上面的运行机制是这样)。
所以这个时候相当于空白 notify_one了一次。实际上 t1 线程的运行只跟 dataReady有关,而跟 condition_variable 无关了。那么这次的notify_one的信号到底去哪里了呢?
不知道我有没有描述清楚问题。有大佬能解答一下吗?