std:: async
|
Definido en el encabezado
<future>
|
||
|
template
<
class
F,
class
...
Args
>
std:: future < /* ver más abajo */ > async ( F && f, Args && ... args ) ; |
(1) | (desde C++11) |
|
template
<
class
F,
class
...
Args
>
std::
future
<
/* ver más abajo */
>
async
(
std::
launch
policy,
|
(2) | (desde C++11) |
La plantilla de función
std::async
ejecuta la función
f
de forma asíncrona (potencialmente en un hilo separado que podría ser parte de un grupo de hilos) y devuelve un
std::future
que eventualmente contendrá el resultado de esa llamada a función.
El tipo de retorno de
std::async
es
std::
future
<
V
>
, donde
V
es:
|
typename
std::
result_of
<
typename
std::
decay
<
F
>
::
type
(
|
(hasta C++17) |
|
std:: invoke_result_t < std:: decay_t < F > , std:: decay_t < Args > ... > . |
(desde C++17) |
|
Si se satisface alguna de las siguientes condiciones, el programa está mal formado:
|
(hasta C++20) |
|
Si alguna de las siguientes es false , el programa está mal formado:
|
(desde C++20) |
La llamada a
std::async
se sincroniza con
la llamada a
f
, y la finalización de
f
está
secuenciada antes
de que el estado compartido esté listo.
Contenidos |
Parámetros
| f | - | Callable objeto a llamar |
| args | - | parámetros a pasar a f |
| policy | - | valor de máscara de bits, donde bits individuales controlan los métodos permitidos de ejecución |
Valor de retorno
std::future
que hace referencia al estado compartido creado por esta llamada a
std::async
.
Políticas de lanzamiento
Invocación asíncrona
Si el indicador
async
está activado, es decir,
(
policy
&
std::
launch
::
async
)
!
=
0
, entonces
std::async
llama
|
INVOKE
(
decay-copy
(
std::
forward
<
F
>
(
f
)
)
,
|
(hasta C++23) |
|
std::
invoke
(
auto
(
std::
forward
<
F
>
(
f
)
)
,
|
(desde C++23) |
como si estuviera en un nuevo hilo de ejecución representado por un std::thread objeto.
|
Las llamadas a decay-copy se evalúan en el hilo actual. |
(hasta C++23) |
|
Los valores producidos por auto son materializados en el hilo actual. |
(desde C++23) |
Si la función
f
retorna un valor o lanza una excepción, se almacena en el estado compartido accesible a través del
std::future
que
std::async
retorna al llamador.
Invocación diferida
Si el indicador
deferred
está activado (es decir,
(
policy
&
std::
launch
::
deferred
)
!
=
0
), entonces
std::async
almacena
|
decay-copy ( std:: forward < F > ( f ) ) y decay-copy ( std:: forward < Args > ( args ) ) ... en el estado compartido. |
(hasta C++23) |
|
auto ( std:: forward < F > ( f ) ) y auto ( std:: forward < Args > ( args ) ) ... en el estado compartido. |
(desde C++23) |
Evaluación perezosa se realiza:
-
La primera llamada a una función de espera no temporizada en el
std::future
que
std::asyncdevolvió al llamador evaluará INVOKE ( std :: move ( g ) , std :: move ( xyz ) ) en el hilo que llamó a la función de espera (que no tiene que ser el hilo que originalmente llamó astd::async), donde
|
(hasta C++23) |
|
(desde C++23) |
- El resultado o la excepción se coloca en el estado compartido asociado con el std::future devuelto y solo entonces se marca como listo. Todos los accesos posteriores al mismo std::future devolverán el resultado inmediatamente.
Otras políticas
Si ni std::launch::async ni std::launch::deferred , ni ningún indicador de política definido por la implementación está establecido en policy , el comportamiento es indefinido.
Selección de políticas
Si se establece más de una bandera, está definido por la implementación qué política se selecciona. Para el valor por defecto (cuando tanto std::launch::async como std::launch::deferred están establecidos en policy ), el estándar recomienda (pero no requiere) utilizar la concurrencia disponible y diferir cualquier tarea adicional.
Si se elige la política std::launch::async ,
-
una llamada a una función de espera en un objeto de retorno asíncrono que comparte el estado compartido creado por esta
std::asyncllamada se bloquea hasta que el hilo asociado haya completado, como si se uniera, o hasta que se agote el tiempo de espera; y - la finalización del hilo asociado synchronizes-with el retorno exitoso de la primera función que está esperando en el estado compartido, o con el retorno de la última función que libera el estado compartido, lo que ocurra primero.
Excepciones
Lanza
- std::bad_alloc , si no se puede asignar memoria para las estructuras de datos internas, o
-
std::system_error
con condición de error
std::errc::resource_unavailable_try_again
, si
policy
==
std::
launch
::
async
y la implementación no puede iniciar un nuevo hilo.
- Si policy es std:: launch :: async | std:: launch :: deferred o tiene bits adicionales establecidos, recurrirá a la invocación diferida o a las políticas definidas por la implementación en este caso.
Notas
La implementación puede extender el comportamiento de la primera sobrecarga de
std::async
permitiendo bits adicionales (definidos por la implementación) en la política de lanzamiento por defecto.
Ejemplos de políticas de lanzamiento definidas por la implementación son la política síncrona (ejecutar inmediatamente, dentro de la llamada
std::async
) y la política de tarea (similar a
std::async
, pero las variables locales de hilo no se limpian)
Si el
std::future
obtenido de
std::async
no se mueve ni se vincula a una referencia, el destructor del
std::future
bloqueará al final de la expresión completa hasta que la operación asíncrona finalice, haciendo esencialmente síncrono código como el siguiente:
std::async(std::launch::async, []{ f(); }); // el dtor del temporal espera a f() std::async(std::launch::async, []{ g(); }); // no comienza hasta que f() se complete
Tenga en cuenta que los destructores de los
std::future
obtenidos por medios distintos a una llamada a
std::async
nunca se bloquean.
Ejemplo
#include <algorithm> #include <future> #include <iostream> #include <mutex> #include <numeric> #include <string> #include <vector> std::mutex m; struct X { void foo(int i, const std::string& str) { std::lock_guard<std::mutex> lk(m); std::cout << str << ' ' << i << '\n'; } void bar(const std::string& str) { std::lock_guard<std::mutex> lk(m); std::cout << str << '\n'; } int operator()(int i) { std::lock_guard<std::mutex> lk(m); std::cout << i << '\n'; return i + 10; } }; template<typename RandomIt> int parallel_sum(RandomIt beg, RandomIt end) { auto len = end - beg; if (len < 1000) return std::accumulate(beg, end, 0); RandomIt mid = beg + len / 2; auto handle = std::async(std::launch::async, parallel_sum<RandomIt>, mid, end); int sum = parallel_sum(beg, mid); return sum + handle.get(); } int main() { std::vector<int> v(10000, 1); std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n'; X x; // Llama a (&x)->foo(42, "Hello") con política por defecto: // puede imprimir "Hello 42" concurrentemente o diferir ejecución auto a1 = std::async(&X::foo, &x, 42, "Hello"); // Llama a x.bar("world!") con política diferida // imprime "world!" cuando se llama a a2.get() o a2.wait() auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!"); // Llama a X()(43); con política async // imprime "43" concurrentemente auto a3 = std::async(std::launch::async, X(), 43); a2.wait(); // imprime "world!" std::cout << a3.get() << '\n'; // imprime "53" } // si a1 no ha terminado en este punto, el destructor de a1 imprime "Hello 42" aquí
Salida posible:
The sum is 10000 43 world! 53 Hello 42
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a estándares publicados anteriormente de C++.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 2021 | C++11 |
tipo de retorno incorrecto y categoría de valor
de los argumentos poco clara en el caso diferido |
tipo de retorno corregido y
aclarado que se utilizan rvalues |
| LWG 2078 | C++11 |
no estaba claro si
std::system_error
puede lanzarse si policy especifica otras políticas de lanzamiento además de std::launch::async |
solo puede lanzarse si
policy == std:: launch :: async |
| LWG 2100 | C++11 |
las funciones de espera temporizada no podían agotar el tiempo
si se utiliza la política std::launch::async |
permitido |
| LWG 2120 | C++11 |
el comportamiento no estaba claro si no se establece ninguna
política estándar o definida por la implementación |
el comportamiento es
indefinido en este caso |
| LWG 2186 | C++11 |
no estaba claro cómo se manejan el valor retornado y la
excepción lanzada desde la evaluación diferida |
se almacenan en
el estado compartido |
| LWG 2752 | C++11 |
std::async
podría no lanzar
std::bad_alloc
si la
memoria para las estructuras de datos internas no puede asignarse |
lanza |
| LWG 3476 | C++20 |
(los tipos decaídos de)
F
y los tipos de argumentos
se requerían directamente que fueran movibles |
eliminados estos requisitos [1] |
- ↑ La capacidad de construcción por movimiento ya está indirectamente requerida por std::is_constructible_v .
Véase también
|
(C++11)
|
espera un valor que se establece de forma asíncrona
(plantilla de clase) |
|
Documentación de C++
para
Biblioteca de soporte de ejecución
|
|