std::barrier
来自cppreference.com
在标头 <barrier> 定义
|
||
template< class CompletionFunction = /* 见下文 */ > class barrier; |
(C++20 起) | |
类模板 std::barrier
提供一种线程协调机制,阻塞已知大小的线程组直至该组中的所有线程到达该屏障。不同于 std::latch,屏障是可重用的:一旦到达的线程组被解除阻塞,即可重用同一屏障。与 std::latch 不同,会在线程解除阻塞前执行一个可能为空的可调用对象。
屏障对象的生存期由一个或多个屏障阶段组成。每个阶段定义一个阻塞线程的阶段同步点。线程可以抵达屏障,但通过调用 arrive
来推迟它在阶段同步点上的等待。这样的线程可以随后再通过调用 wait
在阶段同步点上阻塞。
屏障 阶段 由以下步骤组成:
- 每次调用
arrive
或arrive_and_drop
减少期待计数。 - 期待计数抵达零时,运行阶段完成步骤,即调用
completion
,并解除所有在阶段同步点上阻塞的线程。完成步骤的结束强先发生于所有从完成步骤所除阻的调用的返回。
在期待计数抵达零后,一个线程会在其调用arrive
、arrive_and_drop
或wait
的过程中执行完成步骤恰好一次,但如果没有线程调用wait
则是否执行完成步骤为实现定义。 - 完成步骤结束时,重置期待计数为构造中指定的值,它可能为
arrive_and_drop
调用所调整,自此开始下一阶段。
并发调用barrier
除了析构函数外的成员函数不会引起数据竞争。
模板形参
CompletionFunction | - | 函数对象类型 |
-CompletionFunction 必须满足可移动构造 (MoveConstructible) 和 可析构 (Destructible) 。std::is_nothrow_invocable_v<CompletionFunction&> 必须为 true。
|
CompletionFunction
的默认模板实参是未指定的函数对象类型,它还满足可默认构造 (DefaultConstructible) 。以无实参调用其左值无效果。
成员对象
名称 | 定义 |
completion (私有)
|
CompletionFunction 类型的完成函数对象,在每个阶段完成步骤调用。(仅用于阐述的成员对象*) |
成员类型
名称 | 定义 |
arrival_token
|
未指定的对象类型,满足可移动构造 (MoveConstructible) 、可移动赋值 (MoveAssignable) 及可析构 (Destructible) |
成员函数
构造 barrier (公开成员函数) | |
销毁 barrier (公开成员函数) | |
operator= [弃置] |
barrier 不可赋值 (公开成员函数) |
到达屏障并减少期待计数 (公开成员函数) | |
在阶段同步点阻塞,直至运行其阶段完成步骤 (公开成员函数) | |
到达屏障并把期待计数减少一,然后阻塞直至当前阶段完成 (公开成员函数) | |
将后继阶段的初始期待计数和当前阶段的期待计数均减少一 (公开成员函数) | |
常量 | |
[静态] |
实现所支持的期待计数的最大值 (公开静态成员函数) |
注解
功能特性测试宏 | 值 | 标准 | 功能特性 |
---|---|---|---|
__cpp_lib_barrier |
201907L | (C++20) | std::barrier
|
202302L | (C++20) (DR) |
放松的阶段完成保证 |
示例
运行此代码
#include <barrier> #include <iostream> #include <string> #include <syncstream> #include <thread> #include <vector> int main() { const auto workers = {"Anil", "Busara", "Carl"}; auto on_completion = []() noexcept { // 此处无需锁定 static auto phase = "... 完成\n" "清理...\n"; std::cout << phase; phase = "... 完成\n"; }; std::barrier sync_point(std::ssize(workers), on_completion); auto work = [&](std::string name) { std::string product = " " + name + " 已工作\n"; std::osyncstream(std::cout) << product; // OK, op<< 的调用是原子的 sync_point.arrive_and_wait(); product = " " + name + " 已清理\n"; std::osyncstream(std::cout) << product; sync_point.arrive_and_wait(); }; std::cout << "启动...\n"; std::vector<std::jthread> threads; threads.reserve(std::size(workers)); for (auto const& worker : workers) threads.emplace_back(work, worker); }
可能的输出:
启动... Anil 已工作 Carl 已工作 Busara 已工作 ... 完成 清理... Busara 已清理 Carl 已清理 Anil 已清理 ... 完成
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
P2588R3 | C++20 | 旧的阶段完成保证可能阻碍硬件加速 | 已放松 |
参阅
(C++20) |
单次使用的线程屏障 (类) |