C++多线程condition_variable未被notify却唤醒的问题咨询
Condition Variable与Mutex工作机制问题解析
问题代码与现象
测试代码
#include<iostream> #include <thread> #include <condition_variable> #include <chrono> using namespace std; int main() { mutex mtx; condition_variable cv; int counter = 0; // after releasing lock, what happens auto fn = [&] (int i) { { unique_lock<mutex> lock(mtx); cv.wait(lock, [&] {return counter % 2 == i;}); std::cout << i << " exited wait " << std::endl; counter++; } std::cout << i << " Sleeping" << std::endl; this_thread::sleep_for(chrono::seconds(1)); std::cout << "Printing " << i << std::endl; cv.notify_all(); }; thread t0(fn, 0); thread t1(fn, 1); t0.join(); t1.join(); return 0; }
正常运行输出
0 exited wait 0 Sleeping 1 exited wait 1 Sleeping Printing 0 Printing 1
注释cv.notify_all()后的输出
0 exited wait 0 Sleeping Printing 0 ** Process Stopped **
问题
- 第一种情况中,线程t1的cv为何未被notify就唤醒?
- 为何注释notify_all()后程序无法正常运行,尽管该语句在第一种情况中似乎是最后执行的?
解答
问题1:线程t1无需notify就退出wait的原因
cv.wait(lock, pred)的核心逻辑是:
- 先解锁传入的
unique_lock,进入阻塞状态等待通知。 - 被唤醒(或触发虚假唤醒)后,重新获取锁。
- 检查谓词
pred:如果条件满足,直接返回;不满足则重复前两步。
在你的代码执行流程中:
- t0先抢到锁,此时
counter=0,满足自身谓词counter%2==0,直接退出wait,随后counter自增为1,释放锁。 - t1拿到锁后,检查自己的谓词
counter%2==1——此时counter已经是1,条件完全成立,因此不需要进入阻塞等待阶段,直接退出wait。
这不是“未被notify就唤醒”,而是t1获取锁后谓词条件已满足,根本没进入等待状态。
问题2:注释notify_all()后程序卡住的原因
注释cv.notify_all()后:
- t0执行完所有逻辑,
counter变为1,但没有发送任何通知信号。 - t1启动后第一次抢锁时,
counter=0不满足自身谓词counter%2==1,因此进入cv.wait()的阻塞状态,等待通知唤醒。 - 主线程执行
t0.join()后t0已结束,但t1.join()会一直等待t1完成,而t1卡在cv.wait()中永远无法被唤醒,最终进程无法正常结束,出现Process Stopped。
第一种情况中t0的notify_all()看似最后执行,实则是为了覆盖极端场景(比如t1先抢锁的情况),确保线程被唤醒后检查谓词。你的测试场景中t1没用到这个notify,但不代表它是冗余的。
内容的提问来源于stack exchange,提问作者unknown_jy
相关产品推荐
相关产品推荐

