std::condition_variable必须与std::mutex配合使用,所有共享状态访问须加锁,wait()需用while循环+谓词防虚假唤醒,其生命周期须长于等待线程,不可拷贝移动,不支持跨进程或微秒级超时。

std::condition_variable 必须和 std::mutex 一起用
单独声明 std::condition_variable 没有意义,它不管理共享状态,只负责“等待条件成立”和“通知等待者”。所有对共享变量的读写都必须在 std::mutex 保护下进行,否则会触发未定义行为——哪怕只是 wait() 前的条件检查。
常见错误是漏掉锁:比如先判断 data_ready == false,再调 cv.wait(),但这个判断没加锁。正确做法是把判断逻辑放进 wait() 的谓词(lambda 或函数对象)里,由 wait() 自动在每次唤醒后重新加锁并检查。
-
wait()内部会自动解锁传入的std::unique_lock,并在被唤醒后重新加锁,所以传入的锁必须是已上锁状态 - 永远不要手动在
wait()前解锁,也不要在wait()返回后假设锁还开着——它一定已重新上锁 - 如果用
wait_for()或wait_until(),超时返回时锁也一定已重新上锁
用 while 循环 + 谓词 wait,别用 if + notify_one
std::condition_variable 不保证“唤醒即条件成立”,可能被虚假唤醒(spurious wakeup),也可能多个线程同时被唤醒但只有一个能处理任务。所以必须用 while 循环检查条件,而不是 if。
典型结构是:while (!condition_met) cv.wait(lock)。配合 notify_one() 或 notify_all() 使用时,也要确保通知前已修改共享状态并保持互斥——也就是说,notify_* 应该在持有同一把锁的前提下调用(虽然标准允许不加锁调用,但容易出竞态)。
- 用
notify_one()更高效,适用于“一个任务、一个消费者”的场景;用notify_all()更稳妥,适用于条件可能影响多个等待者(如多个线程等不同事件) - 不要在锁外修改条件再调
notify_*,否则可能出现:修改完成 → 通知发出 → 消费者还没开始 wait → 等待永久挂起 - 谓词推荐用 lambda:
cv.wait(lock, [&]{ return data_ready; });,比裸指针或函数指针更安全清晰
std::condition_variable 的生命周期必须长于所有等待线程
如果 std::condition_variable 对象析构时还有线程在 wait(),程序直接崩溃(通常是 SIGABRT 或 undefined behavior)。这不是资源泄漏,而是未定义行为。
这意味着:不能在局部作用域创建它然后启动后台线程去等待;也不能在线程 join 前就让 cv 所在对象被销毁。常见踩坑点是把 cv 放在 std::thread 的栈上,或者用 std::shared_ptr 管理但没同步好释放顺序。
- 推荐将
std::condition_variable和关联的std::mutex、共享数据一起放在同一个类里,由类生命周期统一管理 - 如果必须动态管理,确保所有
wait()都已返回(例如通过设置退出标志 +notify_all()+ join 所有线程)后再销毁cv -
std::condition_variable不可拷贝不可移动,只能默认构造或析构
std::condition_variable 是系统级原语,不跨进程、不支持超时精度微秒级
它底层依赖操作系统事件机制(Linux 上是 futex,Windows 上是 SRW lock + event),所以不能用于进程间同步;它的超时参数是 std::chrono::duration,但实际精度取决于系统调度器,通常最低是毫秒级,不要指望 wait_for(100ns) 能精确响应。
另外,std::condition_variable 不提供“带超时的 notify”或“等待多个条件”,这些需要自己封装或换用其他机制(如 std::future / std::promise 或第三方库)。
- 跨进程同步请用
boost::interprocess::condition_variable或 POSIX semaphores / shared memory - 需要高精度定时唤醒,请结合
std::this_thread::sleep_for()+ 循环检查,或改用std::timed_mutex配合轮询 - 等待多个独立条件?考虑用多个
cv+ 多个锁,或改用std::future组合
最易被忽略的是:wait() 返回不等于条件成立,也不等于有人调了 notify——它只表示“可能有事发生了”,必须重检状态。这和直觉相悖,却是避免死锁和逻辑错乱的关键。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











