c++ - proceso - libreria para fork en c
¿Async siempre utiliza otro subproceso/núcleo/proceso en C++? (3)
Como sé, async
ejecuta una función en otro hilo / proceso / núcleo y no bloquea el hilo principal, pero ¿es siempre el caso?
Tengo el siguiente código:
async(launch::async,[]()
{
Sleep(1000);
puts("async");
});
puts("main");
Imprime async main
, ¿eso significa que el hilo principal espera hasta que finalice la async
?
Si cambio a lo siguiente:
auto f = async(launch::async,[]() // add "auto f = "
{
Sleep(1000);
puts("async");
});
puts("main");
Imprime la main async
. Esto hace que parezca que main no espera que la async
termine.
Como sé, async ejecuta una función en otro hilo / proceso / núcleo y no bloquea el hilo principal, pero ¿sucede siempre?
std::async
está garantizado para ejecutarse en un hilo separado solo si se pasa std::launch::async
como primer argumento:
std::launch::async
: se inicia un nuevo hilo para ejecutar la tarea de forma asíncronastd::launch::deferred
la tarea se ejecuta en el hilo de llamada la primera vez que se solicita su resultado (evaluación diferida)
La política de lanzamiento predeterminada es std::launch::async | std::launch::deferred
std::launch::async | std::launch::deferred
.
std::async
devuelve std::future
. El destructor std::future
se bloqueará solo si se devuelve el futuro de std::async
:
estas acciones no se bloquearán para que el estado compartido esté listo, excepto que puede bloquear si todo lo siguiente es verdadero: el estado compartido fue creado por una llamada a std :: async, el estado compartido aún no está listo, y esto fue la última referencia al estado compartido
En su primer fragmento de código, crea una expresión rvalue que se destruye inmediatamente , por lo que
"async"
se imprimirá antes de"main"
.La función anónima Async se crea y comienza a ejecutarse.
La función anónima Async se destruye.
main
ejecuciónmain
está bloqueada hasta que se complete la función."async"
está impreso.
main
execucciónmain
reanuda.-
"main"
está impreso.
-
En su segundo fragmento de código, crea una expresión lvalue cuya duración está vinculada a la variable
f
.f
se destruirá al final del alcance de la funciónmain
; por lo tanto,"main"
se imprimirá antes de"async"
debido alDelay(1000)
.La función anónima Async se crea y comienza a ejecutarse.
- Hay un
Delay(1000)
que retrasa la"async"
de la impresión inmediata.
- Hay un
main
ejecuciónmain
continúa.-
"main"
está impreso.
-
Fin del alcance principal.
La función anónima Async se destruye.
main
ejecuciónmain
está bloqueada hasta que se complete la función."async"
está impreso.
Imprime
async main
, ¿eso significa que el hilo principal espera hasta que finalice laasync
?
Sí, lo hace, pero eso se debe a que no captura el futuro devuelto de async
. async
es especial porque el future
regresó de bloques en el destructor hasta que el hilo se completa. Ya que no captura el future
devuelto
async(launch::async,[]()
{
Sleep(1000);
puts("async");
});
debe finalizar antes de que se haga progreso en el hilo actual, ya que el future
devuelto se destruye al final de la expresión.
Imprime la
main async
. Esto hace que parezca que main no espera que laasync
termine.
Que es lo que realmente quieres cuando llamas a async
. Como ha capturado el futuro, su hilo principal puede continuar mientras se completa la tarea asincrónica. Como tiene un retraso en ese hilo, main
se va a imprimir antes del hilo.
Si pasa std::launch::async
, std::async
debe ejecutar la tarea como si se ejecutara en su propio hilo.
El único concepto de enhebrar en C ++ es std::thread
.
std::async
devuelve un std::future
con una propiedad única; si se destruye, se bloquea al completar la tarea almacenada en std::async
. Esto lo atrapa cuando no puede capturar el valor de retorno; el std::future
devuelto es un temporal sin nombre que aparece y se destruye al "final de esa línea".
Esta destrucción espera a que se complete la tarea async
.
En el caso en que lo almacene, este retraso espera hasta que se destruya la variable f
, que está al final de la línea main
, que está después de que imprimimos.
Tenga en cuenta que al menos una implementación principal de C ++ 11, MSVC 2015 y 2017 tiene, en el mejor de los casos, marginalmente compatible std::async
que usa un grupo de subprocesos en lugar de nuevos subprocesos. Este grupo de subprocesos significa que un conjunto de llamadas async
de larga ejecución puede privar de la ejecución a otras llamadas async
.
El uso de un grupo de subprocesos es legal (siempre que reproduzca cualquier subprocesos locales), pero debe evitar la inanición y crear nuevos subprocesos si todos los subprocesos existentes están ocupados durante "demasiado tiempo".
Es marginalmente compatible porque el estándar solo establece que los hilos "deberían" adelantar el progreso. Los hilos que nunca progresan por motivos aleatorios son legales bajo C ++; y en sentido podría argumentar que es lo que std::async
emula en esos casos, pasando así la prueba de si-si.