std::counting_semaphore的初始值即最大资源数,构造后不可动态调整,必须重建对象才能变更容量;其计数可累积,而binary_semaphore仅限0/1状态且release超限时行为未定义。
std::counting_semaphore 的初始值就是最大资源数
它不提供运行时动态调整容量的接口,
在构造时就锁死了能同时通行的线程上限。比如
表示最多 2 个线程能同时持有许可;设成
就是纯阻塞信号量,等同于二元信号量的“初始不可用”状态。
常见错误是误以为能像某些第三方库那样调用
或类似方法扩容——C++20 标准里没有这个能力。资源数变更必须靠重建对象(注意:这会丢失当前所有等待线程的状态)。
初始化值必须是非负整数,负值触发编译期断言失败(
)
模板参数
是底层计数类型的最大安全位宽,不是资源数;实际资源数由构造参数决定
若资源数很大(如百万级),
可能比
更省内存,但要注意溢出风险
acquire() 和 release() 的语义与典型误用
是阻塞式申请一个许可,
是归还一个许可。两者都保证原子性,但
永远不会阻塞(即使当前计数已达最大值,标准允许它静默忽略或抛异常,实践中主流实现(libstd
c++
、libc++)选择忽略)。
最容易踩的坑是:在未成功
前就调用
,或者重复
导致计数超过初始值——这不违法,但会破坏你对“资源数”的建模逻辑。例如你用信号量保护 3 个数据库连接,却意外
了 5 次,后续
就可能拿到“虚高”的许可。
立即学习
“
C++免费学习笔记(深入)
”;
Trae win
Trae Windows 官方版本现已全面支持 Win10 和 Win11 系统(64位)。国内开发者可直接访问 Trae 中文官网(trae.cn 或 trae.com.cn),一键下载官方正版 .exe 安装包,享受国内直连的高速稳定体验。安装过程极其简便,双击即可运行,并支持一键无缝导入 VS Code 或 Cursor 的原有主题、快捷键及插件配置。登录支持手机号、微信或稀土掘金账号。内置免费的豆包与 DeepSeek 等顶级大模型,让你开箱即用,轻松开启高效的 AI 智能编程之旅。
下载
务必配对使用:每个逻辑上的“进入临界区”对应一次
,每个“退出”对应一次
推荐用 RAII 封装,比如自定义
,避免异常绕过
可做非阻塞探测,返回
,适合超时或轮询场景
和 std::binary_semaphore 的关键区别在哪
是
的别名,但语义更严格:它的内部计数只允许 0 或 1,
在已为 1 时行为未定义(libstdc++ 直接 abort)。而
允许计数累积,只要不超过模板参数
所隐含的位宽上限(例如
最大支持 65535)。
所以不要因为“只需要互斥”就默认选
——如果你的场景存在“先批量释放再统一获取”(比如生产者攒够 N 个任务才通知消费者),那只有
能自然表达。
性能上,
在部分平台可能有更轻量的底层实现(如基于 futex 的单比特操作)
可读性上,用
能向协作者明确传达“这里只允许 0/1 状态”
二者都不能跨进程共享,仅限同一进程内线程间同步
Windows 和 Linux 下的兼容性现实
libc++(Clang)和 libstdc++(GCC ≥11)均已实现
,但依赖系统原语:
在 Linux 用
,在 Windows 上回退到
+ 自旋;
在 Windows 需要
支持,否则编译失败。
如果你的目标平台包含老旧 Android(NDK r21 及更早)或某些嵌入式 STL,很可能压根没实现该类——此时别硬套,改用
+
手写计数逻辑更稳妥。
检查是否可用:#ifdef __cpp_lib_semaphore 判断语言特性宏
避免在信号处理函数中调用任何 semaphore 方法(非异步信号安全)
调试时注意:GDB 对 semaphore 内部状态通常不友好,建议用日志打点
/
调用位置
实际用起来最麻烦的往往不是语法,而是想清楚“谁负责归还”和“归还时机是否覆盖所有路径”,尤其是涉及异常、early-return、lambda 捕获的场景。
initial_countstd::counting_semaphore{2}{0}set_capacity()static_assertNstd::counting_semaphoreacquire()release()release()acquire()release()release()release()acquire()acquire()release()semaphore_guardrelease()try_acquire()boolstd::binary_semaphorestd::counting_semaphorerelease()counting_semaphoreNbinary_semaphorecounting_semaphorebinary_semaphorebinary_semaphorestd::counting_semaphorelibstdc++futexCRITICAL_SECTIONlibc++Winelibstd::mutexstd::condition_variableacquirerelease