C++20 semaphore

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

  1. counting_semaphore 是一个轻量同步元件,能控制对共享资源的访问。不同于 std::mutex 、 counting_semaphore 允许同一资源有多于一个同时访问,至少允许 LeastMaxValue 个同时的访问者若LeastMaxValue 为负则程序为谬构。
  2. 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创建有名对象时,是进程级别的。


  1. 线程支持库 ↩︎

  2. semaphores、latch、barrier ↩︎

  3. 标准库头文件 <semaphore> ↩︎

  4. std::counting_semaphore ↩︎

信号量(Semaphore)是一种用于控制多线程并发访问共享资源的同步机制。在C语言中,我们可以使用信号量来实现线程之间的互斥和同步。 在C语言中,信号量的实现通常使用系统提供的信号量库函数。其中,最常用的是计数信号量(Counting Semaphore)。计数信号量具有一个内部计数器,用于记录当前可用的资源数量。当线程需要访问共享资源时,它会尝试获取一个资源。如果计数器的值大于0,线程会成功获取资源并将计数器的值减1;如果计数器的值等于0,线程会被阻塞,直到有其他线程释放资源并增加计数器的值。 在引用中的代码示例中,我们可以看到使用了计数信号量(counting_semaphore)。在主线程中,通过调用`sm.release(1)`来释放一个资源,相当于V操作;而在线程函数中,通过调用`sm.acquire()`来获取一个资源,相当于P操作。这样就实现了线程之间的同步和互斥。 在引用中的代码示例中,同样使用了计数信号量(counting_semaphore)。在三个线程函数中,分别使用不同的信号量来控制线程的执行顺序和打印的内容。通过调用`sema.release()`、`semb.release()`和`semc.release()`来释放资源,相当于V操作;而通过调用`sema.acquire()`、`semb.acquire()`和`semc.acquire()`来获取资源,相当于P操作。这样就实现了线程之间的同步和顺序执行。 构造和赋值函数(counting_semaphore)用于创建和初始化计数信号量对象。其中,`counting_semaphore(desired)`用于构造一个计数信号量对象,并将计数器的初始值设置为desired。 总结起来,C语言中的信号量(Semaphore)是一种用于控制多线程并发访问共享资源的同步机制。通过计数信号量(counting_semaphore),我们可以实现线程之间的同步和互斥,以及按照指定顺序执行线程的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值