std::barrier
| Definiert in Header <barrier> |
||
| template< class CompletionFunction = /* siehe unten */ > class barrier; |
(seit C++20) | |
Die Klassenvorlage std::barrier stellt einen Mechanismus zur Thread-Koordination bereit, der eine Gruppe von Threads bekannter Größe blockiert, bis alle Threads dieser Gruppe die Barriere erreicht haben. Im Gegensatz zu std::latch sind Barrieren wiederverwendbar: Sobald eine Gruppe ankommender Threads freigegeben wird, kann die Barriere wiederverwendet werden. Im Gegensatz zu std::latch führen Barrieren eine möglicherweise leere aufrufbare Funktion aus, bevor sie Threads freigibt.
Die Lebensdauer eines Barrier-Objekts besteht aus einer oder mehreren Phasen. Jede Phase definiert einen Phasensynchronisationspunkt, an dem wartende Threads blockieren. Threads können die Barriere erreichen, das Warten auf den Phasensynchronisationspunkt jedoch durch Aufrufen von arrive aufschieben. Solche Threads können später durch Aufrufen von wait auf dem Phasensynchronisationspunkt blockieren.
Eine Barrier-Phase besteht aus den folgenden Schritten
- Der erwartete Zähler wird bei jedem Aufruf von
arriveoderarrive_and_dropdekrementiert. - Wenn der erwartete Zähler Null erreicht, wird der Phasenabschluss-Schritt ausgeführt, d.h. die
completionwird aufgerufen und alle Threads, die auf dem Phasensynchronisationspunkt blockiert sind, werden freigegeben. Das Ende des Abschluss-Schritts happens-before an alle Aufrufe, die durch den Abschluss-Schritt freigegeben wurden, bevor sie zurückkehren.
Genau einmal nach Erreichen von Null des erwarteten Zählers führt ein Thread den Abschluss-Schritt während seines Aufrufs vonarrive,arrive_and_dropoderwaitaus, außer dass es implementierungsabhängig ist, ob der Schritt ausgeführt wird, wenn kein Threadwaitaufruft. - Wenn der Abschluss-Schritt beendet ist, wird der erwartete Zähler auf den bei der Konstruktion angegebenen Wert zurückgesetzt, abzüglich der Anzahl der Aufrufe von
arrive_and_dropseitdem, und die nächste Barrier-Phase beginnt.
Gleichzeitige Aufrufe der Memberfunktionen von barrier, außer dem Destruktor, führen keine Datenrennen ein.
Inhalt |
[edit] Template-Parameter
| CompletionFunction | - | ein Funktionsobjekttyp |
-CompletionFunction muss die Anforderungen von MoveConstructible und Destructible erfüllen. std::is_nothrow_invocable_v<CompletionFunction&> muss true sein. | ||
Das Standard-Template-Argument von CompletionFunction ist ein nicht spezifizierter Funktionsobjekttyp, der zusätzlich die Anforderungen von DefaultConstructible erfüllt. Das Aufrufen eines Lvalues davon ohne Argumente hat keine Auswirkungen.
[edit] Member-Typen
| Name | Definition |
arrival_token
|
ein nicht spezifizierter Objekttyp, der die Anforderungen von MoveConstructible, MoveAssignable und Destructible erfüllt |
[edit] Datenmember
| Mitglied | Definition |
CompletionFunction completion |
ein Completion-Funktionsobjekt, das bei jedem Phasenabschluss-Schritt aufgerufen wird ((exposition-only member object*) |
[edit] Memberfunktionen
konstruiert ein barrier(public member function) | |
zerstört die barrier(public member function) | |
| operator= [gelöscht] |
barrier ist nicht zuweisbar(öffentliche Memberfunktion) |
| erreicht die Barriere und dekrementiert den erwarteten Zähler (public member function) | |
| blockiert am Phasensynchronisationspunkt, bis sein Phasenabschluss-Schritt ausgeführt wird (public member function) | |
| erreicht die Barriere und dekrementiert den erwarteten Zähler um eins, dann blockiert, bis die aktuelle Phase abgeschlossen ist (public member function) | |
| dekrementiert sowohl den anfänglich erwarteten Zähler für nachfolgende Phasen als auch den erwarteten Zähler für die aktuelle Phase um eins (public member function) | |
Konstanten | |
| [static] |
der maximale Wert des erwarteten Zählers, der von der Implementierung unterstützt wird (public static member function) |
[edit] Anmerkungen
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_barrier |
201907L |
(C++20) | std::barrier
|
202302L |
(C++20) (DR) |
Gelockerte Garantien für den Phasenabschluss |
[edit] Beispiel
#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); }
Mögliche Ausgabe
Starting... Anil worked Carl worked Busara worked ... done Cleaning up... Busara cleaned Carl cleaned Anil cleaned ... done
[edit] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| P2588R3 | C++20 | Alte Garantien für den Phasenabschluss könnten Hardwarebeschleunigung verhindern | gelockert |
[edit] Siehe auch
| (C++20) |
einmalig verwendbare Thread-Barriere (Klasse) |