std::counting_semaphore, std::binary_semaphore

来自cppreference.com
< cpp‎ | thread
 
 
线程支持库
线程
(C++11)
(C++20)
(C++20)
this_thread 命名空间
(C++11)
(C++11)
(C++11)
互斥
(C++11)
通用锁管理
(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
(C++11)
(C++11)
条件变量
(C++11)
信号量
counting_semaphorebinary_semaphore
(C++20)(C++20)
闩与屏障
(C++20)
(C++20)
future
(C++11)
(C++11)
(C++11)
(C++11)
 
 
定义于头文件 <semaphore>
template<std::ptrdiff_t LeastMaxValue = /* implementation-defined */>
class counting_semaphore;
(1) (C++20 起)
using binary_semaphore = std::counting_semaphore<1>;
(2) (C++20 起)
1) counting_semaphore 是一个轻量同步元件,能控制对共享资源的访问。不同于 std::mutexcounting_semaphore 允许同一资源有多于一个同时访问,至少允许 LeastMaxValue 个同时的访问者若LeastMaxValue 为负则程序为谬构。
2) binary_semaphorestd::counting_semaphore 的特化的别名,其 LeastMaxValue1 。实现可能将 binary_semaphore 实现得比 std::counting_semaphore 的默认实现更高效。

counting_semaphore 含有由构造函数初始化的内部计数器。由调用 acquire() 与相关方法减少此计数器,而它通过调用 release() 增加。计数器为零时, acquire() 阻塞该计数器直至它增加,但 try_acquire() 不阻塞; try_acquire_for()try_acquire_until() 阻塞直至计数器增加或到达时限。

类似 std::condition_variablewait()counting_semaphoretry_acquire() 可能虚假地失败。

std::counting_semaphore 的特化非可默认构造 (DefaultConstructible) 可复制构造 (CopyConstructible) 可移动构造 (MoveConstructible) 可复制赋值 (CopyAssignable) 可移动赋值 (MoveAssignable)

成员函数

构造 counting_semaphore
(公开成员函数)
销毁 counting_semaphore
(公开成员函数)
operator=
[被删除]
counting_semaphore 不可赋值
(公开成员函数)
操作
增加内部计数器并除阻获取者
(公开成员函数)
减少内部计数器或阻塞到直至能如此
(公开成员函数)
尝试减少内部计数器而不阻塞
(公开成员函数)
尝试减少内部计数器,至多阻塞一段时长
(公开成员函数)
尝试减少内部计数器,阻塞直至一个时间点
(公开成员函数)
常量
[静态]
返回内部计数器的最大可能值
(公开静态成员函数)

注解

如其名所示, LeastMaxValue最小的最大值,而非实际最大值。从而 max() 能产生大于 LeastMaxValue 的值。

不同于 std::mutexcounting_semaphore 不捆绑到执行线程——能在不同于释放信号量的线程获取该信号量。能同时进行 counting_semaphore 上的所有操作而无需联系到任何特定的执行线程,除了不能同时执行,但能在一个不同的线程上执行析构函数。

信号量亦常用于发信/提醒而非互斥,通过初始化该信号量为 0 从而阻塞尝试 acquire() 的接收者,直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作 std::condition_variable 的替用品,通常它有更好的性能。

示例

#include <iostream>
#include <thread>
#include <chrono>
#include <semaphore>
using namespace std::literals; 
 
// 全局二元信号量实例
// 设置对象计数为零
// 对象在未被发信状态
std::binary_semaphore smphSignal(0);
 
void ThreadProc()
{
    // 通过尝试减少信号量的计数等待来自主程序的信号
    smphSignal.acquire();
 
    // 此调用阻塞直至信号量的计数被从主程序增加
 
    std::cout << "[thread] Got the signal" << std::endl; // 回应消息
 
    // 等待 3 秒以模仿某种线程正在进行的工作
    std::this_thread::sleep_for(3s);
 
    std::cout << "[thread] Send the signal\n"; // 消息
 
    // 对主程序回复发信
    smphSignal.release();
}
 
int main()
{
    // 创建某个背景工作线程,它将长期存在
    std::jthread thrWorker(ThreadProc);
 
    std::cout << "[main] Send the signal\n"; // 消息
 
    // 通过增加信号量的计数对工作线程发信以开始工作
    smphSignal.release();
 
    // release() 后随 acquire() 可以阻止工作线程获取信号量,所以添加延迟:
    std::this_thread::sleep_for(50ms);
 
    // 通过试图减少信号量的计数等待直至工作线程完成工作
    smphSignal.acquire();
 
    std::cout << "[main] Got the signal\n"; // 回应消息
}

输出:

[main] Send the signal
[thread] Got the signal
[thread] Send the signal
[main] Got the signal