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,flagindica quefya se llamó,call_onceregresa de inmediato (tal llamada acall_oncese conoce como pasiva).
- De lo contrario,
call_onceinvoca astd::forward<Callable>(f)con los argumentosstd::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_oncese 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_oncese conoce como excepcional). - Si esa invocación retorna/regresa normalmente (tal llamada a
call_oncese conoce como retornante), la bandera se invierte, y se garantiza que todas las demás llamadas acall_oncecon 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.
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. |
Valor de retorno
(Ninguno)
Excepciones
- std::system_error Si cualquier condición impide que las llamadas a
call_oncese ejecuten como se especifica. - Cualquier excepción lanzada por
f.
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.
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 vez
std::cout << "lanzar: call_once lo intentará de nuevo\n";
throw std::exception();
}
// garantizado una vez
std::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
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. |
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
| |