You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 **

问题

  1. 第一种情况中,线程t1的cv为何未被notify就唤醒?
  2. 为何注释notify_all()后程序无法正常运行,尽管该语句在第一种情况中似乎是最后执行的?

解答

问题1:线程t1无需notify就退出wait的原因

cv.wait(lock, pred)的核心逻辑是:

  1. 先解锁传入的unique_lock,进入阻塞状态等待通知。
  2. 被唤醒(或触发虚假唤醒)后,重新获取锁。
  3. 检查谓词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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 14:47:04