C++ condition_variable::wait 运行行为不符合官方预期?
条件变量测试代码异常卡死的原因分析
核心异常根因
代码无法按预期运行的本质是修改完共享状态后遗漏了通知动作,结合带谓词的wait的官方执行逻辑拆解:
- 带谓词的
cv.wait(lk, pred)的实现与官方说明完全一致:
执行流程为:while (!pred()) { wait(lock); }- 等待线程先持有锁,立刻执行一次谓词校验,若条件不成立才会释放锁、挂起自身
- 线程收到通知/触发虚假唤醒后,会先重新获取锁,再重新执行谓词校验,若条件仍不成立,会再次释放锁、回到挂起状态
- 对照你写的
signals函数执行时序:- 等待1秒后,你直接调用
cv.notify_all()唤醒所有等待线程:此时全局变量i仍为0,所有被唤醒的线程重新校验谓词i==1时发现条件不成立,会立刻重新进入挂起状态,不会退出等待 - 等待1秒后,你在锁的保护下把
i修改为1、完成满足唤醒条件的状态变更后,把后续的cv.notify_all()注释掉了:处于挂起状态的线程永远收不到状态变更的通知,也就没有机会重新校验谓词条件,会永久阻塞,最终导致主线程执行join时永久卡死
- 等待1秒后,你直接调用
容易踩的认知误区
带谓词的wait仅能规避虚假唤醒带来的逻辑偏差,并不会自动监听共享变量的状态变化:
- 只要修改了能满足唤醒条件的共享状态,必须主动调用
notify_one/notify_all发送通知,等待线程才有机会退出阻塞 - 通知动作不需要在持有锁的状态下执行,修改完共享变量、释放锁之后再发通知,还能避免被唤醒的线程因立刻抢锁失败再次阻塞,获得更优的运行性能
修复方案
只需把signals函数末尾被注释的cv.notify_all()取消注释,在修改完i=1的共享状态、释放锁之后发送通知,等待线程被唤醒后重新校验谓词发现条件成立,就会正常退出等待流程,代码即可按预期运行。
内容的提问来源于stack exchange,提问作者Raviteja Narra
相关产品推荐
相关产品推荐

