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
Definido en el encabezado <mutex>
template < class Callable, class ... Args >
void call_once ( std:: once_flag & flag, Callable && f, Args && ... args ) ;
(desde C++11)

Ejecuta el objeto Callable f exactamente una vez, incluso si se llama concurrentemente desde varios hilos.

En detalle:

  • Si, para el momento en que se llama a std::call_once , flag indica que f ya fue llamado, std::call_once retorna inmediatamente (dicha llamada a std::call_once se conoce como pasiva ).
  • En caso contrario, std::call_once llama a INVOKE ( std:: forward < Callable > ( f ) , std:: forward < Args > ( args ) ... ) . A diferencia del constructor de std::thread o de std::async , los argumentos no se mueven ni copian porque no necesitan transferirse a otro hilo de ejecución (dicha llamada a std::call_once se conoce como activa ).
  • Si esa invocación lanza una excepción, se propaga al llamador de std::call_once , y flag no se activa para que se intente otra llamada (dicha llamada a std::call_once se conoce como excepcional ).
  • Si esa invocación retorna normalmente (dicha llamada a std::call_once se conoce como de retorno ), flag se activa, y todas las demás llamadas a std::call_once con el mismo flag están garantizadas de ser pasivas .

Todas las activas llamadas en la misma flag forman un único orden total que consiste en cero o más excepcionales llamadas, seguidas por una retornante llamada. El final de cada activa llamada sincroniza-con la siguiente activa llamada en ese orden.

El retorno de la llamada activa sincroniza-con los retornos de todas las llamadas pasivas en el mismo flag : esto significa que todas las llamadas concurrentes a std::call_once están garantizadas de observar cualquier efecto secundario realizado por la llamada activa , sin sincronización adicional.

Contenidos

Parámetros

flag - un objeto para el cual se ejecuta exactamente una función
f - Callable objeto a invocar
args... - argumentos para pasar a la función

Valor de retorno

(ninguno)

Excepciones

  • std::system_error si alguna condición impide que las llamadas a std::call_once se ejecuten según lo especificado.
  • Cualquier excepción lanzada por f .

Notas

Si llamadas concurrentes a std::call_once pasan diferentes funciones f , no está especificado cuál f será ejecutada. La función seleccionada se ejecuta en el mismo hilo que la invocación de std::call_once a la que fue pasada.

La inicialización de variables estáticas locales de función está garantizada que ocurra solo una vez incluso cuando se llama desde múltiples hilos, y puede ser más eficiente que el código equivalente usando std::call_once .

El equivalente POSIX de esta función es pthread_once .

Ejemplo

#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"; // esto puede aparecer más de una vez
        throw std::exception();
    }
    std::cout << "Did not throw, call_once will not attempt again\n"; // garantizado una vez
}
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();
}

Salida posible:

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

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 2080 C++11 std::invalid_argument sería lanzado si f es inválido,
pero el escenario donde f se invalida no está especificado
eliminada esta condición de error
LWG 2442 C++11 los argumentos eran copiados y/o movidos antes de la invocación no se realiza copia/traslado

Véase también

(C++11)
objeto auxiliar para garantizar que call_once invoque la función solo una vez
(clase)
Documentación C para call_once