Namespaces
Variants

std:: counting_semaphore, std:: binary_semaphore

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
counting_semaphore binary_semaphore
(C++20) (C++20)
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
定义于头文件 <semaphore>
template < std:: ptrdiff_t LeastMaxValue = /* 由实现定义 */ >
class counting_semaphore ;
(1) (C++20 起)
using binary_semaphore = std :: counting_semaphore < 1 > ;
(2) (C++20 起)
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 的特化不满足 可默认构造 可复制构造 可移动构造 可复制赋值 可移动赋值 的要求。

目录

数据成员

成员名称 定义
counter (private) 类型为 std::ptrdiff_t 的内部计数器。
( 仅用于说明的成员对象* )

成员函数

构造 counting_semaphore
(公开成员函数)
析构 counting_semaphore
(公开成员函数)
operator=
[deleted]
counting_semaphore 不可赋值
(公开成员函数)
操作
递增内部计数器并解除获取者的阻塞
(公开成员函数)
递减内部计数器或在无法递减时阻塞
(公开成员函数)
尝试非阻塞地递减内部计数器
(公开成员函数)
尝试递减内部计数器,最多阻塞一段时长
(公开成员函数)
尝试递减内部计数器,阻塞直到某个时间点
(公开成员函数)
常量
[static]
返回内部计数器的最大可能值
(公开静态成员函数)

注释

正如其名称所示, LeastMaxValue 是指 最小 最大值,而非 实际 最大值。因此 max() 可能返回大于 LeastMaxValue 的数值。

std::mutex 不同, counting_semaphore 不与执行线程绑定——例如,获取信号量的操作可以在与释放信号量不同的线程上执行。 counting_semaphore 的所有操作都可以并发执行,且与特定执行线程无关,但析构函数除外:它不能并发执行,但可以在不同线程上执行。

信号量也常用于信号传递/通知的语义而非互斥,通过将信号量初始化为 0 来阻塞尝试 acquire() 的接收方,直到通知方通过调用 release ( n ) 进行"信号发送"。在这方面,信号量可被视为 std::condition_variable 的替代方案,且通常具有更优性能。

功能测试 标准 功能
__cpp_lib_semaphore 201907L (C++20) std::counting_semaphore , std::binary_semaphore

示例

#include <chrono>
#include <iostream>
#include <semaphore>
#include <thread>
// 全局二进制信号量实例
// 对象计数设置为零
// 对象处于非触发状态
std::binary_semaphore
    smphSignalMainToThread{0},
    smphSignalThreadToMain{0};
void ThreadProc()
{
    // 通过尝试减少信号量计数来等待主进程的信号
    smphSignalMainToThread.acquire();
    // 此调用将阻塞,直到主进程增加信号量计数
    std::cout << "[thread] Got the signal\n"; // 响应消息
    // 等待3秒以模拟线程正在执行某些工作
    // 由线程完成
    using namespace std::literals;
    std::this_thread::sleep_for(3s);
    std::cout << "[thread] Send the signal\n"; // 消息
    // 向主进程发送信号
    smphSignalThreadToMain.release();
}
int main()
{
    // 创建工作线程
    std::thread thrWorker(ThreadProc);
    std::cout << "[main] Send the signal\n"; // 消息
    // 通过增加信号量计数通知工作线程开始工作
    smphSignalMainToThread.release();
    // 通过尝试减少信号量计数等待工作线程完成工作
    smphSignalThreadToMain.acquire();
    std::cout << "[main] Got the signal\n"; // 响应消息
    thrWorker.join();
}

输出:

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