std::call_once
| Definiert in Header <mutex> |
||
| template< class Callable, class... Args > void call_once( std::once_flag& flag, Callable&& f, Args&&... args ); |
(seit C++11) | |
Führt das Callable-Objekt f genau einmal aus, auch wenn es gleichzeitig von mehreren Threads aufgerufen wird.
Im Detail
- Wenn zum Zeitpunkt des Aufrufs von
std::call_oncedas flag anzeigt, dass f bereits aufgerufen wurde, kehrtstd::call_oncesofort zurück (ein solcher Aufruf vonstd::call_oncewird als passiv bezeichnet).
- Andernfalls ruft
std::call_onceauf INVOKE(std::forward<Callable>(f), std::forward<Args>(args)...). Im Gegensatz zum Konstruktor von std::thread oder zu std::async werden die Argumente nicht verschoben oder kopiert, da sie nicht an einen anderen Ausführungsthread übergeben werden müssen (ein solcher Aufruf vonstd::call_oncewird als aktiv bezeichnet).
- Wenn diese Invokation eine Ausnahme auslöst, wird sie an den Aufrufer von
std::call_onceweitergegeben, und flag wird nicht umgeschaltet, sodass ein weiterer Aufruf versucht wird (ein solcher Aufruf vonstd::call_oncewird als exceptionell bezeichnet). - Wenn diese Invokation normal zurückkehrt (ein solcher Aufruf von
std::call_oncewird als rückkehrend bezeichnet), wird flag umgeschaltet, und alle anderen Aufrufe vonstd::call_oncemit demselben flag werden garantiert passiv sein.
- Wenn diese Invokation eine Ausnahme auslöst, wird sie an den Aufrufer von
Alle aktiven Aufrufe für dasselbe flag bilden eine einzige totale Ordnung, die aus null oder mehr exceptionellen Aufrufen gefolgt von einem rückkehrenden Aufruf besteht. Das Ende jedes aktiven Aufrufs synchronisiert sich mit dem nächsten aktiven Aufruf in dieser Reihenfolge.
Die Rückgabe des rückkehrenden Aufrufs synchronisiert sich mit den Rückgaben aller passiven Aufrufe für dasselbe flag: Dies bedeutet, dass alle gleichzeitigen Aufrufe von std::call_once garantiert alle Nebeneffekte des aktiven Aufrufs beobachten, ohne zusätzliche Synchronisierung.
Inhalt |
[edit] Parameter
| flag | - | ein Objekt, für das genau eine Funktion ausgeführt wird |
| f | - | Callable-Objekt, das aufgerufen werden soll |
| args... | - | Argumente, die an die Funktion übergeben werden sollen |
[edit] Rückgabewert
(keine)
[edit] Ausnahmen
- std::system_error, wenn eine Bedingung Aufrufe von
std::call_oncedaran hindert, wie spezifiziert ausgeführt zu werden. - Jede von f ausgelöste Ausnahme.
[edit] Anmerkungen
Wenn gleichzeitige Aufrufe von std::call_once verschiedene Funktionen f übergeben, ist nicht spezifiziert, welche f aufgerufen wird. Die ausgewählte Funktion läuft im selben Thread wie die std::call_once-Invocation, an die sie übergeben wurde.
Die Initialisierung von funktionslokalen statischen Variablen ist garantiert nur einmal erfolgreich, auch wenn sie von mehreren Threads aufgerufen wird, und kann effizienter sein als der äquivalente Code, der std::call_once verwendet.
Das POSIX-Äquivalent dieser Funktion ist pthread_once.
[edit] Beispiel
#include <iostream> #include <mutex> #include <thread> std::once_flag flag1, flag2; void simple_do_once() { std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; }); } void may_throw_function(bool do_throw) { if (do_throw) { std::cout << "Throw: call_once will retry\n"; // this may appear more than once throw std::exception(); } std::cout << "Did not throw, call_once will not attempt again\n"; // guaranteed once } void do_once(bool do_throw) { try { std::call_once(flag2, may_throw_function, do_throw); } catch (...) {} } int main() { std::thread st1(simple_do_once); std::thread st2(simple_do_once); std::thread st3(simple_do_once); std::thread st4(simple_do_once); st1.join(); st2.join(); st3.join(); st4.join(); std::thread t1(do_once, true); std::thread t2(do_once, true); std::thread t3(do_once, false); std::thread t4(do_once, true); t1.join(); t2.join(); t3.join(); t4.join(); }
Mögliche Ausgabe
Simple example: called once Throw: call_once will retry Throw: call_once will retry Throw: call_once will retry Did not throw, call_once will not attempt again
[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 |
|---|---|---|---|
| LWG 2080 | C++11 | std::invalid_argument würde ausgelöst werden, wenn f ungültig ist, aber das Szenario, in dem f ungültig wird, ist nicht spezifiziert |
entfernte diese Fehlerbedingung |
| LWG 2442 | C++11 | Die Argumente wurden vor der Invokation kopiert und/oder verschoben | Es wird kein Kopieren/Verschieben durchgeführt |
[edit] Siehe auch
| (C++11) |
Hilfsobjekt, das sicherstellt, dass call_once die Funktion nur einmal aufruft (Klasse) |
| C-Dokumentation für call_once
| |