理解C++20中的std::counting_semaphore和std::binary_semaphore
摘要
本文讲解C++20的std::counting_semaphore和std::binary_semaphore,涵盖其API、用于限制并发和线程间信号传递的用法,以及重要细节。
<p><a href="https://lobste.rs/s/safj18/understanding_std_counting_semaphore">评论</a></p>
查看缓存全文
缓存时间: 2026/08/08 22:38
# 理解 C++20 的 std::counting_semaphore 和 std::binary_semaphore
Source: https://www.cppstories.com/2026/semaphore/
## 目录
- 基础 (https://www.cppstories.com/2026/semaphore/#basics)
- API (https://www.cppstories.com/2026/semaphore/#api)
- 使用 `std::counting_semaphore` 限制并发 (https://www.cppstories.com/2026/semaphore/#limiting-concurrency-with-stdcounting_semaphore)
- 使用 RAII 归还槽位 (https://www.cppstories.com/2026/semaphore/#returning-a-slot-with-raii)
- 使用 `std::binary_semaphore` 进行信令 (https://www.cppstories.com/2026/semaphore/#signaling-with-stdbinary_semaphore)
- 带超时的等待 (https://www.cppstories.com/2026/semaphore/#waiting-with-a-timeout)
- 信号量、互斥量还是条件变量? (https://www.cppstories.com/2026/semaphore/#semaphore-mutex-or-condition-variable)
- 值得了解的细节 (https://www.cppstories.com/2026/semaphore/#details-worth-knowing)
- `LeastMaxValue` 是一个下界 (https://www.cppstories.com/2026/semaphore/#leastmaxvalue-is-a-lower-bound)
- 不要将计数器增加到 `max()` 以上 (https://www.cppstories.com/2026/semaphore/#do-not-increase-the-counter-past-max)
- `try_acquire()` 可能假性失败 (https://www.cppstories.com/2026/semaphore/#try_acquire-may-fail-spuriously)
- 不保证等待顺序 (https://www.cppstories.com/2026/semaphore/#waiting-order-is-not-guaranteed)
- 注意生命周期 (https://www.cppstories.com/2026/semaphore/#watch-the-lifetime)
- 总结 (https://www.cppstories.com/2026/semaphore/#summary)
- 参考 (https://www.cppstories.com/2026/semaphore/#references)
本文解释了 C++20 中引入的两种信号量类型:`std::counting_semaphore` 和 `std::binary_semaphore`。我们首先使用计数信号量来限制同一时间可以操作的线程数量。然后使用二进制信号量在线程之间发送信号。我们还会探讨超时等待、一个小型 RAII 辅助类以及其他一些细节。
> **注意:** 这里讨论的同步功能在 C++20 中可用。示例使用 C++23 的 `std::println` 以得到更清晰的输出。我们开始吧。
## 基础
互斥量在每次只允许一个线程进入受保护区域时效果很好。但有时这个限制过于严格。想象一个应用程序拥有三个数据库连接。如果每次只运行一个数据库操作,就会浪费其中两个连接。另一方面,允许任意数量的线程开始操作可能会使数据库过载。我们需要的是一种限制:三个线程可以继续执行,而其余线程等待。
还有另一种常见情况。一个线程准备数据,另一个线程等待数据就绪。信号量可以很好地解决这两个问题。许多多线程库都有信号量,但 C++20 标准库现在直接提供了信号量,这非常酷。
## API
计数信号量声明为:
`std::counting_semaphore`
主要操作如下:
| 函数 | 描述 |
|------|------|
| `counting_semaphore(desired)` | 创建计数器设置为 `desired` 的信号量 |
| `acquire()` | 减少计数器;如果为零则等待
相似文章
C++ 非对称内存栅栏的细节
深入探讨 C++ 并发中的非对称线程栅栏,涵盖 C++ 提案 P1202R0 及其通过 Linux membarrier() 系统调用的实现,并附有来自 Folly 同步原语的示例。
使用:counters和:atomics模块在Erlang中快速计数
这篇技术文章解释了如何使用Erlang的:counters和:atomics模块进行高性能计数和共享可变状态,从而突破标准的进程隔离模型。内容涵盖BEAM运行时中的原子操作,如add_get、exchange和compare-and-swap(比较并交换)。
C++26:更多函数包装器
C++26 引入了两个新的函数包装器:std::copyable_function(提供了可复制且 const 正确的 std::function 替代品)和 std::function_ref(一个非拥有、可调用的引用,具有引用语义)。
Thoroughly Understanding C++ ABI
A deep dive into C++ ABI, explaining binary interface concepts, CPU/OS dependencies, object file formats like ELF and PE32+, and calling conventions.
C语言中的Go风格并发
一篇详细的技术文章,探讨如何在C语言中复制Go的并发模型,使用POSIX线程、互斥锁、条件变量和工作池,作为Solod转译器项目的一部分。