std::barrier
来自 cppreference.cn
定义于头文件 <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) 的要求。用无参数调用它的左值没有效果。
[编辑] 成员类型
名称 | 定义 |
arrival_token
|
一个未指定对象类型,满足 可移动构造 (MoveConstructible)、可移动赋值 (MoveAssignable) 和 可析构 (Destructible) 的要求 |
[编辑] 数据成员
成员 | 定义 |
CompletionFunction completion |
一个完成函数对象,它在每个阶段完成步骤中被调用 (仅用于阐释的成员对象*) |
[编辑] 成员函数
构造一个 barrier (public member function) | |
销毁 barrier (public member function) | |
operator= [已删除] |
barrier 不可赋值(公开成员函数) |
到达屏障并递减预期计数 (public member function) | |
在阶段同步点阻塞,直到其阶段完成步骤运行 (public member function) | |
到达屏障并递减预期计数一,然后阻塞直到当前阶段完成 (public member function) | |
将后续阶段的初始预期计数和当前阶段的预期计数都递减一 (public member function) | |
常量 | |
[静态] |
实现支持的最大预期计数值 (public static member function) |
[编辑] 注意
特性测试宏 | 值 | 标准 | 特性 |
---|---|---|---|
__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 { // 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::osyncstream(std::cout) << product; // ok, op<< call is atomic sync_point.arrive_and_wait(); product = " " + name + " cleaned\n"; std::osyncstream(std::cout) << product; sync_point.arrive_and_wait(); }; std::cout << "Starting...\n"; std::vector<std::jthread> threads; threads.reserve(std::size(workers)); for (auto const& worker : workers) threads.emplace_back(work, worker); }
可能的输出
Starting... Anil worked Carl worked Busara worked ... done Cleaning up... Busara cleaned Carl cleaned Anil cleaned ... done
[编辑] 缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
P2588R3 | C++20 | 旧的阶段完成保证可能会阻止硬件加速 | 已放宽 |
[编辑] 参阅
(C++20) |
一次性线程屏障 (class) |