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(); }
你推测的死锁场景完全命中关键
- f2先抢到锁,发现i=0,把i改成1,调用
cv.notify_one()后释放锁- 但因为i的修改没有通过互斥锁的同步机制让f1可见(或者f1检查i时的逻辑有漏洞),f1抢到锁后读取到的是缓存里的旧值0
- f1误以为i还没到1,进入
cv.wait()等待,同时释放锁- 接着f2再次抢到锁,看到i=1,也进入
cv.wait()等待- 两个线程都卡在等待状态,没人再发通知,死锁就这么发生了
问题根源:条件变量的使用违反了两个核心规则
- 内存同步依赖互斥锁:互斥锁不只是用来防止多线程同时修改临界资源,还负责刷新内存——持有锁时的读写操作,会让其他线程在获取锁后看到最新的值。如果读取i时没持有锁,或者检查条件的时机不对,就会读到过期的缓存值。
- 必须用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
相关产品推荐
相关产品推荐

