Namespaces
Variants

std:: call_once

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
(C++11)
(C++11)
(C++11)
call_once
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
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, selbst wenn es gleichzeitig von mehreren Threads aufgerufen wird.

Im Detail:

  • Falls zum Zeitpunkt des Aufrufs von std::call_once der flag anzeigt, dass f bereits aufgerufen wurde, kehrt std::call_once sofort zurück (ein solcher Aufruf von std::call_once wird als passiv bezeichnet).
  • Andernfalls ruft std::call_once INVOKE ( std:: forward < Callable > ( f ) , std:: forward < Args > ( args ) ... ) auf. Im Gegensatz zum std::thread -Konstruktor oder std::async werden die Argumente nicht verschoben oder kopiert, da sie nicht an einen anderen Ausführungs-Thread übertragen werden müssen (ein solcher Aufruf von std::call_once wird als aktiv bezeichnet).
  • Wenn dieser Aufruf eine Exception wirft, wird sie an den Aufrufer von std::call_once weitergegeben, und das flag wird nicht umgeschaltet, sodass ein weiterer Aufruf versucht wird (ein solcher Aufruf von std::call_once wird als exceptional bezeichnet).
  • Wenn dieser Aufruf normal zurückkehrt (ein solcher Aufruf von std::call_once wird als returning bezeichnet), wird das flag umgeschaltet, und alle anderen Aufrufe von std::call_once mit demselben flag sind garantiert passive .

Alle aktiven Aufrufe auf derselben flag bilden eine einzige Gesamtordnung, bestehend aus null oder mehreren exceptional Aufrufen, gefolgt von einem returning Aufruf. Das Ende jedes aktiven Aufrufs synchronisiert sich mit dem nächsten aktiven Aufruf in dieser Ordnung.

Die Rückkehr vom returning Aufruf synchronisiert-sich mit den Rückkehren aller passive Aufrufe auf derselben flag : dies bedeutet, dass alle gleichzeitigen Aufrufe von std::call_once garantiert alle Nebeneffekte beobachten können, die durch den active Aufruf erzeugt wurden, ohne zusätzliche Synchronisation.

Inhaltsverzeichnis

Parameter

flag - ein Objekt, für das genau eine Funktion ausgeführt wird
f - Callable aufzurufendes Objekt
args... - an die Funktion zu übergebende Argumente

Rückgabewert

(keine)

Ausnahmen

  • std::system_error falls irgendeine Bedingung Aufrufe von std::call_once an der Ausführung gemäß Spezifikation hindert.
  • Jede Ausnahme, die von f geworfen wird.

Hinweise

Wenn gleichzeitige Aufrufe von std::call_once unterschiedliche Funktionen f übergeben, ist nicht spezifiziert, welche f aufgerufen wird. Die ausgewählte Funktion wird im selben Thread ausgeführt wie der std::call_once -Aufruf, an den sie übergeben wurde.

Die Initialisierung von funktionslokalen Static-Variablen ist garantiert nur einmalig, selbst wenn sie von mehreren Threads aufgerufen wird, und kann effizienter sein als der entsprechende Code mit std::call_once .

Das POSIX-Äquivalent dieser Funktion ist pthread_once .

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"; // dies kann mehrfach erscheinen
        throw std::exception();
    }
    std::cout << "Did not throw, call_once will not attempt again\n"; // garantiert einmalig
}
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

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
LWG 2080 C++11 std::invalid_argument würde ausgelöst, wenn f ungültig ist,
aber das Szenario, in dem f ungültig wird, ist nicht spezifiziert
diesen Fehlerzustand entfernt
LWG 2442 C++11 die Argumente wurden vor dem Aufruf kopiert und/oder verschoben kein Kopieren/Verschieben wird durchgeführt

Siehe auch

(C++11)
Hilfsobjekt zur Sicherstellung, dass call_once die Funktion nur einmal aufruft
(Klasse)
C-Dokumentation für call_once