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
Défini dans l'en-tête <mutex>
template < class Callable, class ... Args >
void call_once ( std:: once_flag & flag, Callable && f, Args && ... args ) ;
(depuis C++11)

Exécute l'objet Callable f exactement une fois, même s'il est appelé simultanément depuis plusieurs threads.

En détail :

  • Si, au moment où std::call_once est appelé, flag indique que f a déjà été appelée, std::call_once retourne immédiatement (un tel appel à std::call_once est qualifié de passif ).
  • Sinon, std::call_once appelle INVOKE ( std:: forward < Callable > ( f ) , std:: forward < Args > ( args ) ... ) . Contrairement au constructeur de std::thread ou à std::async , les arguments ne sont ni déplacés ni copiés car ils n'ont pas besoin d'être transférés vers un autre thread d'exécution (un tel appel à std::call_once est qualifié d' actif ).
  • Si cet appel lève une exception, elle est propagée à l'appelant de std::call_once , et le flag n'est pas basculé de sorte qu'un autre appel sera tenté (un tel appel à std::call_once est qualifié d' exceptionnel ).
  • Si cet appel retourne normalement (un tel appel à std::call_once est qualifié de retournant ), flag est basculé, et tous les autres appels à std::call_once avec le même flag sont garantis d'être passifs .

Tous les appels actifs sur le même flag forment un ordre total unique composé de zéro ou plusieurs appels exceptionnels , suivis d'un appel de retour . La fin de chaque appel actif se synchronise-avec le prochain appel actif dans cet ordre.

Le retour de l'appel actif se synchronise-avec les retours de tous les appels passifs sur le même flag : cela signifie que tous les appels concurrents à std::call_once sont garantis d'observer tous les effets de bord produits par l'appel actif , sans synchronisation supplémentaire.

Table des matières

Paramètres

flag - un objet pour lequel exactement une fonction est exécutée
f - Callable objet à invoquer
args... - arguments à passer à la fonction

Valeur de retour

(aucun)

Exceptions

  • std::system_error si une condition quelconque empêche les appels à std::call_once de s'exécuter comme spécifié.
  • Toute exception levée par f .

Notes

Si des appels concurrents à std::call_once passent différentes fonctions f , il n'est pas spécifié quelle f sera appelée. La fonction sélectionnée s'exécute dans le même thread que l'invocation std::call_once à laquelle elle a été passée.

L'initialisation des variables statiques locales à une fonction est garantie de se produire une seule fois même lorsqu'elles sont appelées depuis plusieurs threads, et peut être plus efficace que le code équivalent utilisant std::call_once .

L'équivalent POSIX de cette fonction est pthread_once .

Exemple

#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"; // ceci peut apparaître plusieurs fois
        throw std::exception();
    }
    std::cout << "Did not throw, call_once will not attempt again\n"; // garanti une seule fois
}
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();
}

Sortie possible :

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

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement corrigé
LWG 2080 C++11 std::invalid_argument serait levé si f est invalide,
mais le scénario où f est invalidé n'est pas spécifié
cette condition d'erreur a été supprimée
LWG 2442 C++11 les arguments étaient copiés et/ou déplacés avant l'invocation aucune copie/déplacement n'est effectué

Voir aussi

(C++11)
objet d'assistance pour garantir que call_once n'invoque la fonction qu'une seule fois
(classe)
Documentation C pour call_once