std::condition_variable必须与std::unique_lock配合使用,因wait()需锁支持临时释放与重获;须用带谓词的wait(lock,[]{return cond;})避免虚假唤醒;notify_one/notify_all选择取决于语义,析构前须确保无等待线程。

condition_variable 必须和 unique_lock 一起用
单独声明 std::condition_variable 没法工作,它不管理互斥量,只负责挂起/唤醒线程。你必须配一个 std::unique_lock<:mutex></:mutex>,且这个锁在调用 wait() 前必须已持有。
常见错误是传 std::lock_guard 或裸 std::mutex ——编译直接报错,因为 wait() 要求锁支持临时释放和重新获取。
-
wait()会自动释放锁,让其他线程能修改共享状态;被唤醒后自动重新加锁再返回 - 别用
std::mutex直接构造unique_lock后就丢掉——要保持对象生命周期覆盖整个等待过程 - 如果用
std::shared_mutex等非独占锁,condition_variable不支持,得换std::condition_variable_any
wait() 的 predicate 版本不是可选优化,而是必须用
裸 wait(lock) 有惊群和虚假唤醒风险:线程被唤醒时,条件可能根本没满足,或者多个线程同时被唤醒但只有一个能真正处理任务。
所以几乎总该用带谓词的重载:wait(lock, []{ return /* 条件表达式 */; })。它内部自动做 while 循环检查,安全可靠。
立即学习“C++免费学习笔记(深入)”;
- 谓词必须捕获共享变量(如用
[&]),且变量访问需受同一 mutex 保护 - 不要写成
wait(lock); if (x > 0) {...}——这漏掉了虚假唤醒场景 - 谓词里别做耗时操作,否则阻塞其他线程获取锁
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
<p>// 等待方
std::unique_lock<std::mutex> lk(mtx);
cv.wait(lk, []{ return ready; }); // 安全:自动循环检查</p><p>// 通知方
{
std::lock_guard<std::mutex> lk(mtx);
ready = true;
}
cv.notify_one(); // 或 notify_all()notify_one() 和 notify_all() 的选择影响性能与逻辑正确性
notify_one() 只唤醒一个等待线程,notify_all() 唤醒全部。选哪个不只看“快不快”,更要看语义是否匹配。
- 生产者-消费者中单个任务就绪 → 用
notify_one()即可,避免多余唤醒 - 状态变更影响所有等待者(比如“全局关闭标志置位”)→ 必须用
notify_all() - 用
notify_one()但等待线程有多个不同条件(比如等 A 或等 B)→ 可能唤醒错人,导致死锁或饥饿 -
notify_*可以在锁外调用,但要注意:若通知早于wait(),信号会丢失(因为 condition_variable 不保存信号计数)
销毁 condition_variable 前必须确保无等待线程
std::condition_variable 析构时,如果有线程还在 wait(),行为未定义——多数实现会 crash 或 abort。
这不是资源泄漏问题,而是直接 UB。所以实际工程中:
- 把
condition_variable和关联的mutex、共享数据放在同一作用域(如类成员),靠对象生命周期管理 - 退出前手动清理:设置退出标志 +
notify_all()+join()所有等待线程 - 别在 lambda 捕获中隐式延长 condition_variable 生命周期(比如在线程池里存了个引用)
最易忽略的一点:notify_all() 并不保证所有被唤醒线程都已完成执行——你得靠 join 或其他同步机制确认它们真退出了,才能安全析构。











