C++怎么用信号量 C++并发编程条件变量用法【深度】

5次阅读

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

C++怎么用信号量 C++并发编程条件变量用法【深度】

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 计数——多数调试器不识别它,只能靠日志或原子变量打点

事情说清了就结束。信号量不是万能锁,condition_variable 也不是自动状态机;关键在想清楚你要同步的是“资源数量”还是“某个事件是否发生”。

text=ZqhQzanResources