std::barrier
来自cppreference.com
在标头 <barrier> 定义
|
||
template<class CompletionFunction = /* see below */> class barrier; |
(C++20 起) | |
类模板 std::barrier
提供允许至多为期待数量的线程阻塞直至期待数量的线程到达该屏障。不同于 std::latch ,屏障可重用:一旦到达的线程从屏障阶段的同步点除阻,则可重用同一屏障。
屏障对象的生存期由屏障阶段的序列组成。每个阶段定义一个阶段同步点。在阶段中到达屏障的线程能通过调用 wait
在阶段同步点上阻塞,而且将保持阻塞直至运行阶段完成步骤。
屏障阶段由以下步骤组成:
- 每次调用
arrive
或arrive_and_drop
减少期待计数。 - 期待计数抵达零时,运行阶段完成步骤。完成步骤调用完成函数对象,并除阻所有在阶段同步点上阻塞的线程。完成步骤的结束强先发生于所有从完成步骤所除阻的调用的返回。
恰好在期待计数抵达零后,一个线程会在其调用arrive
、arrive_and_drop
或wait
的过程中执行完成步骤,除了如果没有线程调用wait
则是否执行完成步骤为实现定义。 - 完成步骤结束时,重置期待计数为构造中指定的值,可能为
arrive_and_drop
调用所调整,并开始下一阶段。
同时调用 barrier
的成员函数,除了析构函数,不引入数据竞争。
模板形参
CompletionFunction | - | 函数对象类型 |
-CompletionFunction 必须符合可移动构造 (MoveConstructible) 和 可析构 (Destructible) 的要求。std::is_nothrow_invocable_v<CompletionFunction&> 必须为 true 。
|
CompletionFunction
的默认模板实参是未指定的函数对象类型,额外满足可默认构造 (DefaultConstructible) 的要求。以无参数调用其左值无效果。
每个屏障对象表现为如同它保有一个 CompletionFunction
类型的非静态数据成员 completion_
,并在每个阶段完成步骤通过 completion_() 调用它。
成员类型
名称 | 定义 |
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 <thread> #include <vector> int main() { const auto workers = { "anil", "busara", "carl" }; auto on_completion = []() noexcept { // locking not needed here static auto phase = "... done\n" "Cleaning up...\n"; std::cout << phase; phase = "... done\n"; }; std::barrier sync_point(std::ssize(workers), on_completion); auto work = [&](std::string name) { std::string product = " " + name + " worked\n"; std::cout << product; // ok, op<< call is atomic sync_point.arrive_and_wait(); product = " " + name + " cleaned\n"; std::cout << product; sync_point.arrive_and_wait(); }; std::cout << "Starting...\n"; std::vector<std::thread> threads; for (auto const& worker : workers) { threads.emplace_back(work, worker); } for (auto& thread : threads) { thread.join(); } }
可能的输出:
Starting... anil worked carl worked busara worked ... done Cleaning up... busara cleaned carl cleaned anil cleaned ... done
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
P2588R3 | C++20 | 旧的阶段完成保证可能阻碍硬件加速 | 已放松 |
参阅
(C++20) |
单次使用的线程屏障 (类) |