std::barrier
出自 cppreference.com
| 定義於標頭檔 <barrier> |
||
| template< class CompletionFunction = /* 見下文 */ > class barrier; |
(自 C++20 起) | |
類別模板 std::barrier 提供了一種執行緒協調機制,能將一組已知數量的執行緒阻塞,直到該組中所有執行緒皆到達屏障(barrier)。與 std::latch 不同,屏障是可重複使用的:當一組到達的執行緒被解鎖後,屏障即可再次使用。與 std::latch 不同,屏障在解鎖執行緒之前會執行一個可能為空的函式物件。
屏障物件的生命週期由一個或多個階段(phase)組成。每個階段定義了一個「階段同步點」,等待中的執行緒會在此阻塞。執行緒可以到達屏障,但透過呼叫 arrive 來延遲在「階段同步點」上的等待。此類執行緒稍後可以透過呼叫 wait 在「階段同步點」上進行阻塞。
屏障的「階段」包含以下步驟:
- 每當呼叫
arrive或arrive_and_drop時,「預期計數」(expected count)就會遞減。 - 當預期計數達到零時,會執行「階段完成步驟」,這意味著會呼叫
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(公開成員函式) | |
解構 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 { // 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) |
單次使用的執行緒屏障 (類別) |