<p>condition_variable 必须与 unique_lock 配合使用,wait() 内部自动解锁/加锁,仅支持 uniquelock;需用 while 循环检查条件防虚假唤醒;notify* 必须在持锁且更新共享状态后调用;不支持跨进程或信号处理函数。</p>

condition_variable 必须和 unique_lock 配合用
单独声明 condition_variable 没用,它不管理锁,只负责挂起/唤醒线程。你传给 wait() 的必须是 unique_lock<mutex></mutex>,不是 lock_guard<mutex></mutex>,也不是裸 mutex。
-
wait()内部会先调用unlock(),等被唤醒后再自动lock()—— 这个“自动”依赖unique_lock的可移动性和可解锁性 -
lock_guard构造即加锁、析构即释放,不可解锁、不可转移,传给wait()会编译失败 - 别手写
mutex.lock()/unlock()去绕过unique_lock,那会导致wait()行为未定义
虚假唤醒(spurious wakeup)必须用 while 循环检查条件
wait() 返回不代表条件真的满足了,系统可能没原因就唤醒你。直接用 if 判断会出错,比如生产者还没写完数据,消费者就去读了空缓冲区。
- 永远用
while (condition_is_false) cv.wait(lock);,别用if - 条件变量本身不保存状态,它只是通知“可能有变化”,真假得你自己再查一遍共享变量
- 常见错误:把
flag == true当作条件直接if (flag) wait(),这等于没检查
while (!data_ready) {
cv.wait(lock);
}
notify_one() 和 notify_all() 不是“发信号”,而是“踢一下等待队列”
它们不保证唤醒谁、不保证唤醒后立刻执行、也不保证条件真满足。调用时机和条件更新顺序错了,线程就卡死。
- 必须在修改完共享状态 之后、且仍在持有锁时调用
notify_*,否则唤醒的线程一进来就看到旧状态 -
notify_one()只唤醒一个,适合“一个任务一个消费者”的场景;notify_all()唤醒全部,适合广播型通知(如停止标志),但要注意惊群效应 - 不要在锁外调用
notify_*,虽然语法允许,但可能造成唤醒后竞争条件 —— 状态改了,但通知发早了
std::condition_variable 不能用于跨进程或 signal handler
它只在单进程内、同地址空间的线程间有效。想在 fork 后父子进程同步?不行。想在 SIGINT 处理函数里通知主线程?也不行。
立即学习“C++免费学习笔记(深入)”;
-
condition_variable底层依赖 futex(Linux)或 Critical Section(Windows),这些机制不跨进程 - signal handler 是异步上下文,不能安全调用
wait()或notify_*,会破坏锁状态 - 需要跨进程通信,请用
sem_t(POSIX)、命名管道、或消息队列;需要 signal 响应,请用signalfd(Linux)或自设标志 +poll()循环
condition_variable 的难点不在语法,而在状态变更和通知的时序耦合——锁、条件变量、共享变量三者必须严格按序操作,漏掉一个 while、错放一个 notify、或者少持一帧锁,程序就进入不可预测的等待。










