std::call_once
Definido en el archivo de encabezado <mutex> | ||
template<class Callable, class... Args> void call_once(std::once_flag& flag, Callable&& f, Args&&... args); | (desde C++11) | |
Ejecuta el objeto invocable (Callable) f
exactamente una vez, incluso si se llama concurrentemente desde varios hilos.
En detalle:
- Si para el momento en que se llama a
call_once
,flag
indica quef
ya se llamó,call_once
regresa de inmediato (tal llamada acall_once
se conoce como pasiva).
- De lo contrario,
call_once
invoca a std::forward<Callable>(f) con los argumentos std::forward<Args>(args)... (como si fuera por std::invoke). A diferencia del constructor de std::thread o std::async, los argumentos no se mueven ni se copian porque no es necesario transferirlos a otro hilo de ejecución (tal llamada acall_once
se conoce como activa).
- Si esa invocación lanza una excepción, se propaga al llamante de
call_once
, y la bandera no se invierte para que se intente realizar otra llamada (tal llamada acall_once
se conoce como excepcional). - Si esa invocación retorna/regresa normalmente (tal llamada a
call_once
se conoce como retornante), la bandera se invierte, y se garantiza que todas las demás llamadas acall_once
con la misma bandera son pasivas.
- Si esa invocación lanza una excepción, se propaga al llamante de
Todas las llamadas activas en la misma bandera, flag
, forman un solo orden total que consiste en cero o más llamadas excepcionales, seguidas de una llamada retornante. El final de cada llamada activa se sincroniza-con la siguiente llamada activa en ese orden.
El retorno/regreso de la llamada retornante se sincroniza-con los retornos de todas las llamadas pasivas en la misma bandera, flag
: esto significa que se garantiza que todas las llamadas concurrentes a call_once
observan cualquier efecto secundario producido por la llamada activa, sin sincronización adicional.
Contenido |
[editar]Parámetros
flag | - | Un objeto para el cual se ejecuta exactamente una función. |
f | - | Callable Objeto a invocar. |
args... | - | Argumentos a pasar a la función. |
[editar]Valor de retorno
(Ninguno)
[editar]Excepciones
- std::system_error Si cualquier condición impide que las llamadas a
call_once
se ejecuten como se especifica. - Cualquier excepción lanzada por
f
.
[editar]Notas
Si llamadas concurrentes a call_once
pasan diferentes funciones f
, no se especifica cuál f
se llamará. La función seleccionada se ejecuta en el mismo hilo que la invocación call_once
a la que se pasó.
Se garantiza que la inicialización de variables locales estáticas en una función ocurre solamente una vez incluso cuando se llama desde varios hilos, y puede ser más eficiente que el código equivalente que usa std::call_once
.
El equivalente POSIX de esta función es pthread_once.
[editar]Ejemplo
#include <iostream>#include <thread>#include <mutex> std::once_flag flag1, flag2; void una_vez_sencillo(){ std::call_once(flag1, [](){std::cout<<"Ejemplo sencillo: llamado una vez\n";});} void funcion_que_puede_lanzar(bool lanzar){if(lanzar){// esto puede aparecer más de una vezstd::cout<<"lanzar: call_once lo intentará de nuevo\n";throwstd::exception();}// garantizado una vezstd::cout<<"No se lanzó, call_once no lo intentará de nuevo\n";} void hacer_una_vez(bool lanzar){try{ std::call_once(flag2, funcion_que_puede_lanzar, lanzar);}catch(...){}} int main(){std::thread st1(una_vez_sencillo);std::thread st2(una_vez_sencillo);std::thread st3(una_vez_sencillo);std::thread st4(una_vez_sencillo); st1.join(); st2.join(); st3.join(); st4.join(); std::thread t1(hacer_una_vez, true);std::thread t2(hacer_una_vez, true);std::thread t3(hacer_una_vez, false);std::thread t4(hacer_una_vez, true); t1.join(); t2.join(); t3.join(); t4.join();}
Posible salida:
Ejemplo sencillo: llamado una vez lanzar: call_once lo intentará de nuevo lanzar: call_once lo intentará de nuevo No se lanzó, call_once no lo intentará de nuevo
[editar]Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
LWG 2442 | C++11 | Los argumentos se copian y/o mueven antes de la invocación. | No se realiza copia/movimiento. |
[editar]Véase también
(C++11) | Objeto auxiliar para asegurarse que call_once invoque la función una sola vez. (clase) |
Documentación de C para call_once |