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) 的要求。用無引數呼叫它的左值沒有效果。
[編輯] 成員型別
名稱 | 定義 |
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) |