为何操作std::condition_variable关联变量需加锁?含std::atomic场景
关于std::condition_variable中ready变量加锁的疑问解答
为什么修改ready必须加锁(哪怕工作线程处于等待状态)
- 首先要明确:条件变量存在虚假唤醒的可能——工作线程可能在没收到
notify_one()的情况下被唤醒。这时候线程会检查ready的值,如果没加锁,ready的修改和检查之间没有同步机制,线程可能读到旧值,导致逻辑错误。 - 其次,即使没有虚假唤醒,指令重排和内存可见性也是硬伤。不加锁的情况下,CPU或编译器可能调整
ready = true和notify_one()的执行顺序:notify操作先被工作线程感知到,但ready的修改还没刷新到主内存,线程醒来后读到的还是false,又继续等待,这就是你遇到的“bool值没在唤醒前完成修改”的原因。 - 条件变量的使用规范本身就要求:关联的共享状态(比如这里的ready)的修改与检查,必须在同一互斥锁保护下,这是保证状态一致和内存可见性的核心要求。
如果ready是std::atomic类型,还需要加锁吗?
- 依然建议加锁,原因有二:
- atomic只能保证单个变量的原子性和内存可见性,但解决不了虚假唤醒的问题。线程被虚假唤醒后重新检查
ready时,如果没有锁,其他线程可能同时修改ready,导致逻辑混乱。 - 加锁能确保“修改ready”和“调用notify_one()”是一个原子逻辑单元,彻底避免指令重排的风险。虽然atomic的内存序(比如
std::memory_order_release/std::memory_order_acquire)能部分控制顺序,但写法复杂、可读性差,远不如锁稳妥。
- atomic只能保证单个变量的原子性和内存可见性,但解决不了虚假唤醒的问题。线程被虚假唤醒后重新检查
- 当然,极端场景下可以通过严格的内存序设置规避锁,但这种写法极易出错,不推荐在业务代码中使用。
关于你遇到的“不加锁时bool值无法在唤醒前完成修改”的问题
- 这就是指令重排+内存可见性导致的。普通bool变量没有任何内存同步保证,编译器可能把它缓存到寄存器,CPU也可能调整指令顺序:
notify_one()先执行,但ready = true的写操作还没同步到主内存。工作线程被唤醒后,从本地缓存读到的还是旧值,自然会继续等待,看起来就像修改没生效。
内容的提问来源于stack exchange,提问作者Tyler
相关产品推荐
相关产品推荐

