std::condition_variable必须搭配std::mutex和显式共享状态变量,否则会假唤醒或死锁;需用while循环检查条件,notify_one()/notify_all()可在锁外调用但状态更新必须持锁。

std::condition_variable 为什么不能单独用
它必须搭配 std::mutex 和一个**显式的共享状态变量**,否则会假唤醒或死锁。标准库不帮你管“条件是否真满足”,只负责挂起/唤醒线程。
常见错误现象:wait() 返回后直接干活,结果发现条件其实没成立(比如队列还是空的);或者忘了在 notify_one() 前加锁,导致唤醒丢失。
- 永远用
while (condition == false)循环检查,不用if -
notify_one()/notify_all()可以在锁外调用,但修改共享状态时必须持锁 - 别在持有锁时做耗时操作,否则阻塞其他线程——唤醒动作本身很快,但状态更新要快
std::counting_semaphore 在 C++20 怎么初始化和等待
它是真正意义上的信号量:内部维护一个原子计数器,acquire() 减一、release() 加一,不依赖外部状态和互斥锁。
使用场景:限制并发访问数量(如连接池)、控制生产者-消费者节奏、替代简单的二值信号量。
立即学习“C++免费学习笔记(深入)”;
- 构造时传入初始计数值,比如
std::counting_semaphore sem{5};表示最多允许 5 个线程同时通过 -
sem.acquire()阻塞直到计数 > 0,然后原子减一;sem.release()原子加一并可能唤醒等待者 - 注意:C++20 的
std::counting_semaphore不支持超时等待(没有try_acquire_for),需要自己套std::timed_mutex或改用第三方库
condition_variable 和 semaphore 混用会出什么问题
本质冲突:前者是“条件通知机制”,后者是“资源计数机制”。强行混用容易绕晕逻辑,尤其是状态更新和通知顺序错位时。
典型翻车点:用 condition_variable 等待某个资源就绪,却用 semaphore.release() 去“通知”,结果等待线程压根没被唤醒(因为没调 notify_*())。
- 不要用
semaphore替代condition_variable.notify_one()—— 它们语义不同,不可互换 - 如果业务逻辑里既有“等待条件成立”又有“限制并发数”,建议分层:上层用
condition_variable管状态,下层用semaphore控制资源配额 - C++20 起,
std::binary_semaphore可用于替代老式std::mutex+std::condition_variable实现的简单开关,但前提是“不需要判断复杂条件”
Windows/Linux 下 semaphore 兼容性差异在哪
C++20 的 std::counting_semaphore 是跨平台的,但底层实现依赖系统 API:Linux 用 sem_wait/sem_post,Windows 用 CreateSemaphoreEx。一般没问题,但有两处易忽略:
- Windows 上,当计数器为 0 且有线程在
acquire()等待时,若程序异常终止,该 semaphore 可能残留为“已通知”状态,影响下次启动(Linux 通常随进程销毁) - 某些旧版 libc++(如 Android NDK r21)未完全实现
std::counting_semaphore,编译通过但运行时报std::system_error: Function not implemented - 调试时别依赖 IDE 的“线程视图”看 semaphore 计数——多数调试器不识别它,只能靠日志或原子变量打点











