template< class CompletionFunction = /* see below */ >
class barrier;
The class template std::barrier
provides a thread-coordination mechanism that blocks a group of threads of known size until all threads in that group have reached the barrier. Unlike std::latch, barriers are reusable: once a group of arriving threads are unblocked, the barrier can be reused. Unlike std::latch, barriers execute a possibly empty callable before unblocking threads.
A barrier object's lifetime consists of one or more phases. Each phase defines a phase synchronization point where waiting threads block. Threads can arrive at the barrier, but defer waiting on the phase synchronization point by calling arrive
. Such threads can later block on the phase synchronization point by calling wait
.
A barrier phase consists of the following steps:
arrive
or arrive_and_drop
.completion
is invoked, and all threads blocked on the phase synchronization point are unblocked. The end of the completion step strongly happens-before all calls that were unblocked by the completion step return.arrive
, arrive_and_drop
, or wait
, except that it is implementation-defined whether the step executes if no thread calls wait
.arrive_and_drop
since, and the next barrier phase begins.Concurrent invocations of the member functions of barrier
, except for the destructor, do not introduce data races.
The default template argument of CompletionFunction
is an unspecified function object type that additionally meets the requirements of DefaultConstructible. Calling an lvalue of it with no arguments has no effects.
CompletionFunction
completion
a completion function object which is called on every phase completion step
barrier
barrier
barrier
is not assignable
#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); }
Possible output:
Starting... Anil worked Carl worked Busara worked ... done Cleaning up... Busara cleaned Carl cleaned Anil cleaned ... done[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior P2588R3 C++20 old phase completion guarantees might prevent hardware acceleration relaxed [edit] See alsoRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4