命名空间
变体
操作

std::counting_semaphore, std::binary_semaphore

来自 cppreference.cn
< cpp‎ | thread
 
 
并发支持库
线程
(C++11)
(C++20)
this_thread 命名空间
(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)
期物
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
危害指针
原子类型
(C++11)
(C++20)
原子类型的初始化
(C++11)(C++20 中已弃用)
(C++11)(C++20 中已弃用)
内存顺序
(C++11)(C++26 中已弃用)
原子操作的自由函数
原子标志的自由函数
 
 
定义于头文件 <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_semaphorestd::counting_semaphore 的特化版本的别名,其中 LeastMaxValue1。实现可能比 std::counting_semaphore 的默认实现更高效地实现 binary_semaphore

counting_semaphore 包含一个由构造函数初始化的内部计数器。此计数器通过调用 acquire() 和相关方法递减,并通过调用 release() 递增。当计数器为零时,acquire() 会阻塞直到计数器递增,但 try_acquire() 不会阻塞;try_acquire_for()try_acquire_until() 会阻塞直到计数器递增或达到超时。

类似于 std::condition_variable::wait()counting_semaphoretry_acquire() 可能会虚假地失败。

std::counting_semaphore 的特化不是 DefaultConstructibleCopyConstructibleMoveConstructibleCopyAssignableMoveAssignable

内容

[编辑] 数据成员

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

[编辑] 成员函数

构造一个 counting_semaphore
(公有成员函数) [编辑]
析构 counting_semaphore
(公有成员函数) [编辑]
operator=
[已删除]
counting_semaphore 不可赋值
(公有成员函数) [编辑]
操作
递增内部计数器并解除阻塞等待者
(公有成员函数) [编辑]
递减内部计数器或阻塞直到可以递减
(公有成员函数) [编辑]
尝试递减内部计数器而不阻塞
(公有成员函数) [编辑]
尝试递减内部计数器,阻塞最多持续一段时间
(公有成员函数) [编辑]
尝试递减内部计数器,阻塞到某个时间点
(公有成员函数) [编辑]
常量
[静态]
返回内部计数器的最大可能值
(公有静态成员函数) [编辑]

[编辑] 注释

正如其名称所示,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>
 
// global binary semaphore instances
// object counts are set to zero
// objects are in non-signaled state
std::binary_semaphore
    smphSignalMainToThread{0},
    smphSignalThreadToMain{0};
 
void ThreadProc()
{
    // wait for a signal from the main proc
    // by attempting to decrement the semaphore
    smphSignalMainToThread.acquire();
 
    // this call blocks until the semaphore's count
    // is increased from the main proc
 
    std::cout << "[thread] Got the signal\n"; // response message
 
    // wait for 3 seconds to imitate some work
    // being done by the thread
    using namespace std::literals;
    std::this_thread::sleep_for(3s);
 
    std::cout << "[thread] Send the signal\n"; // message
 
    // signal the main proc back
    smphSignalThreadToMain.release();
}
 
int main()
{
    // create some worker thread
    std::thread thrWorker(ThreadProc);
 
    std::cout << "[main] Send the signal\n"; // message
 
    // signal the worker thread to start working
    // by increasing the semaphore's count
    smphSignalMainToThread.release();
 
    // wait until the worker thread is done doing the work
    // by attempting to decrement the semaphore's count
    smphSignalThreadToMain.acquire();
 
    std::cout << "[main] Got the signal\n"; // response message
    thrWorker.join();
}

输出

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