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

C++17原子操作与条件变量死锁问题排查求助

分析你的条件变量死锁问题

兄弟,你对这个死锁场景的推测完全精准!这本质上是内存可见性和条件变量使用规范的问题,咱们一步步把这个问题拆解明白:

先还原你的核心代码逻辑(根据描述推导)

虽然你没贴具体代码,但从你的描述能猜出核心逻辑大概是这样:

int i = 0;
std::mutex mtx;
std::condition_variable cv;

void f1() {
    std::unique_lock<std::mutex> lock(mtx);
    // 这里大概率是检查条件的逻辑有问题,或者内存同步没做好
    if (i != 1) { // 错误:用了if而不是while,或者读取i时没同步
        cv.wait(lock);
    }
    i--;
    cv.notify_one();
}

void f2() {
    std::unique_lock<std::mutex> lock(mtx);
    if (i != 0) {
        cv.wait(lock);
    }
    i++;
    cv.notify_one();
}

你推测的死锁场景完全命中关键

  1. f2先抢到锁,发现i=0,把i改成1,调用cv.notify_one()后释放锁
  2. 但因为i的修改没有通过互斥锁的同步机制让f1可见(或者f1检查i时的逻辑有漏洞),f1抢到锁后读取到的是缓存里的旧值0
  3. f1误以为i还没到1,进入cv.wait()等待,同时释放锁
  4. 接着f2再次抢到锁,看到i=1,也进入cv.wait()等待
  5. 两个线程都卡在等待状态,没人再发通知,死锁就这么发生了

问题根源:条件变量的使用违反了两个核心规则

  1. 内存同步依赖互斥锁:互斥锁不只是用来防止多线程同时修改临界资源,还负责刷新内存——持有锁时的读写操作,会让其他线程在获取锁后看到最新的值。如果读取i时没持有锁,或者检查条件的时机不对,就会读到过期的缓存值。
  2. 必须用while循环检查条件:不能用if,因为线程被唤醒后(不管是被notify唤醒还是虚假唤醒),必须重新检查条件——这时候其他线程可能已经修改了i的值,而重新检查时持有锁,能保证读取到最新的i。

修正后的正确写法

只要把检查条件的if改成while,就能彻底避免这个死锁问题:

void f1() {
    std::unique_lock<std::mutex> lock(mtx);
    // while循环:每次被唤醒后重新检查i,保证内存可见性
    while (i != 1) {
        cv.wait(lock);
    }
    i--;
    cv.notify_one();
}

void f2() {
    std::unique_lock<std::mutex> lock(mtx);
    while (i != 0) {
        cv.wait(lock);
    }
    i++;
    cv.notify_one();
}

额外提一句:cv.wait()被唤醒时会自动重新获取锁,这时候读取i就会触发内存同步,拿到最新的值,彻底避免了读取过期值的问题。

内容的提问来源于stack exchange,提问作者user1413793

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:07:39