C++20 semaphore
01 C++20 semaphore
信号量 (semaphore) 是一种轻量的同步原件,用于制约对共享资源的并发访问。在可以使用两者时,信号量能比条件变量更有效率。1
下面是在 www.open-std.org
对 C++20 semaphore
的一点介绍内容。(semaphores、latch、barrier)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1135r2.html
2
Semaphores are lightweight synchronization primitives used to constrain concurrent access to a shared resource. They are widely used to implement other synchronization primitives and, whenever both are applicable, can be more efficient than condition variables.
A counting semaphore is a semaphore object that models a non-negative resource count. A binary semaphore is a semaphore object that has only two states, also known as available and unavailable. [ Note: A binary semaphore should be more efficient than a counting semaphore with a unit magnitude count. – end note ]信号量是用于限制对共享资源的并发访问的轻量级同步原语。它们被广泛应用于实现其他同步原语,并且,只要两者都适用,就可以比条件变量更有效。
计数信号量是模拟非负资源计数的信号量对象。二进制信号量是一个只有两种状态的信号量对象,也称为可用和不可用。[注意:二进制信号量应该比使用单位数量级计数的计数信号量更有效。–尾注]
cppreference.com
中的标准库头文件 <semaphore>
中也给出了详细定义。3。
C++20 中提供了两个信号量类。(其实binary_semaphore仅仅是counting_semaphore的一个特例。)
信号量类名 | 含义 |
---|---|
counting_semaphore | 实现非负资源计数的信号量 |
binary_semaphore | 仅拥有二个状态的信号量 |
cppreference.com
中给出的关于semaphore的定义如下:
// 概要
namespace std {
template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
class counting_semaphore;
using binary_semaphore = counting_semaphore<1>;
}
// 类模板 std::counting_semaphore
namespace std {
template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
class counting_semaphore {
public:
static constexpr ptrdiff_t max() noexcept;
constexpr explicit counting_semaphore(ptrdiff_t desired);
~counting_semaphore();
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;
void release(ptrdiff_t update = 1);
void acquire();
bool try_acquire() noexcept;
template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
private:
ptrdiff_t counter; // 仅用于阐释
};
}
std::counting_semaphore4
- counting_semaphore 是一个轻量同步元件,能控制对共享资源的访问。不同于 std::mutex 、 counting_semaphore 允许同一资源有多于一个同时访问,至少允许 LeastMaxValue 个同时的访问者若LeastMaxValue 为负则程序为谬构。
- binary_semaphore 是 std::counting_semaphore 的特化的别名,其 LeastMaxValue 为 1 。实现可能将 binary_semaphore 实现得比 std::counting_semaphore 的默认实现更高效。
counting_semaphore 含有由构造函数初始化的内部计数器。由调用 acquire() 与相关方法减少此计数器,而它通过调用 release() 增加。计数器为零时, acquire() 阻塞该计数器直至它增加,但 try_acquire() 不阻塞; try_acquire_for() 与 try_acquire_until() 阻塞直至计数器增加或到达时限。
类似 std::condition_variable 的 wait() , counting_semaphore 的 try_acquire() 可能虚假地失败。
std::counting_semaphore的主要接口
接口 | 含义 |
---|---|
release | 增加内部计数器并除阻获取者 |
acquire | 减少内部计数器或阻塞到直至能如此 |
try_acquire | 尝试减少内部计数器而不阻塞 |
try_acquire_for | 尝试减少内部计数器,至多阻塞一段时长 |
try_acquire_until | 尝试减少内部计数器,阻塞直至一个时间点 |
max | 返回内部计数器的最大可能值(静态,常量) |
注解
如其名所示, LeastMaxValue 是最小的最大值,而非实际最大值。从而 max() 能产生大于 LeastMaxValue 的值。不同于 std::mutex , counting_semaphore 不捆绑到执行线程——能在不同于释放信号量的线程获取该信号量。能同时进行 counting_semaphore 上的所有操作而无需联系到任何特定的执行线程,除了不能同时执行,但能在一个不同的线程上执行析构函数。
信号量亦常用于发信/提醒而非互斥,通过初始化该信号量为 0 从而阻塞尝试 acquire() 的接收者,直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作 std::condition_variable 的替用品,通常它有更好的性能。
semaphore、mutex、condition_variable的区别
信号量 (semaphore) 是一种轻量的同步原件,用于制约对共享资源的并发访问。在可以使用两者时,信号量能比条件变量更有效率。
互斥(mutex)算法避免多个线程同时访问共享资源。这会避免数据竞争,并提供线程间的同步支持。
条件变量(condition_variable)是允许多个线程相互交流的同步原语。它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续。条件变量始终关联到一个互斥。
1: semaphore对acquire和release操作没有限制,可以在不同线程操作;可以仅在线程A里面acquire,仅在线程B里面release。
mutex的lock和unlock必须在同一个线程配对使用;也就是说线程A内mutex如果lock了,必须在线程A内unlock,线程B内lock了,也必须在线程B内unlock。
2: semaphore和mutex是可以独立使用的;condition_variable必须和mutex配对使用。
3: semaphore一般用于控制多个并发资源的访问或者控制并行数量;mutex一般是起到同步访问一个资源的作用。同一时刻,mutex保护的资源只能被一个线程访问;semaphore的保护对象上面是可以有多个线程在访问的。mutex是同步,semaphore是并行。
4: 由于condition_variable和mutex结合使用,condition_variable更多是为了通知、顺序之类的控制。
5: C++语言中的mutex、semaphore、condition和系统级的概念不同。都是线程级别的,也就是不能跨进程控制的。要区别于windows api的 mutex、semaphore、event。windows系统上这几个api创建有名对象时,是进程级别的。