std::barrier
From cppreference.com
| ヘッダ <barrier> で定義 |
||
| template< class CompletionFunction = /* 後述 */ > class barrier; |
(C++20以降) | |
クラステンプレート std::barrier は、既知のサイズのスレッドグループがバリアに到達するまで、そのグループ内のすべてのスレッドをブロックするスレッド協調メカニズムを提供します。std::latch とは異なり、バリアは再利用可能です。つまり、到着したスレッドのグループがブロック解除されると、そのバリアを再利用できます。std::latch とは異なり、バリアはスレッドをブロック解除する前に、空かもしれない呼び出し可能オブジェクトを実行します。
バリアオブジェクトの生存期間は、1つ以上のフェーズで構成されます。各フェーズは、待機中のスレッドがブロックするフェーズ同期点を定義します。スレッドは arrive を呼び出すことでバリアに到達できますが、フェーズ同期点での待機は遅延させることができます。そのようなスレッドは、後で wait を呼び出すことでフェーズ同期点でブロックできます。
バリアのフェーズは、以下のステップで構成されます。
- 期待カウントは、
arriveまたはarrive_and_dropが呼び出されるたびにデクリメントされます。 - 期待カウントがゼロに達すると、フェーズ完了ステップが実行されます。これは、
completionが呼び出され、フェーズ同期点でブロックされていたすべてのスレッドがブロック解除されることを意味します。完了ステップの終了は、完了ステップによってブロック解除されたすべての呼び出しが返るよりも強く先行 (strongly happens-before) します。
期待カウントがゼロになった後、ちょうど一度だけ、あるスレッドが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) | |
| バリアに到達して期待カウントを1つデクリメントし、現在のフェーズが完了するまでブロックする (public member function) | |
| 後続のフェーズの初期期待カウントと現在のフェーズの期待カウントの両方を1つデクリメントする (public member function) | |
定数 | |
| [static] |
実装がサポートする期待カウントの最大値 (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++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| P2588R3 | C++20 | 古いフェーズ完了保証がハードウェアアクセラレーションを妨げる可能性がある | 緩和された |
[編集] 関連項目
| (C++20) |
一度だけ使用可能なスレッドバリア (クラス) |