Espacios de nombres
Variantes
Acciones

std::async

De cppreference.com
< cpp‎ | thread
 
 
Biblioteca de apoyo de concurrencia
Hilos
(C++11)
(C++20)
Espacio de nombres this_thread
(C++11)
(C++11)
(C++11)
Cancelación cooperativa
Exclusión mutua
Gestión genérica de bloqueo
(C++11)
(C++11)
(C++11)
(C++11)
Variables de condición
(C++11)
Semáforos
Pestillos y barreras
(C++20)
(C++20)
Futuros
(C++11)
(C++11)
async
(C++11)
Recuperación segura
Punteros de riesgo
Tipos atómicos
(C++11)
(C++20)
Inicialización de tipos atómicos
(C++11)(en desuso en C++20)
(C++11)(en desuso en C++20)
Orden de memoria
Funciones independientes para operaciones atómicas
Funciones independientes para indicadores atómicos
 
Definido en el archivo de encabezado <future>
(1)
template<class Function, class... Args>

std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>

    async( Function&& f, Args&&... args);
(desde C++11)
(hasta C++17)
template<class Function, class... Args>

std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>

    async( Function&& f, Args&&... args);
(desde C++17)
(hasta C++20)
template<class Function, class... Args>

[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>

    async( Function&& f, Args&&... args);
(desde C++20)
(2)
template<class Function, class... Args>

std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>

    async(std::launch policy, Function&& f, Args&&... args);
(desde C++11)
(hasta C++17)
template<class Function, class... Args>

std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>

    async(std::launch policy, Function&& f, Args&&... args);
(desde C++17)
(hasta C++20)
template<class Function, class... Args>

[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>

    async(std::launch policy, Function&& f, Args&&... args);
(desde C++20)


La plantilla de función async ejecuta la función f asíncronamente (potencialmente en un hilo separado que puede ser parte de una reserva de hilos) y devuelve un std::future que eventualmente contendrá el resultado de esa llamada a función.

1) Se comporta como si se llamara a (2) con policy siendo std::launch::async|std::launch::deferred. En otras palabras, f puede ejecutarse en otro hilo o puede ejecutarse asíncronamente cuando el std::future resultante es consultado por un valor.
2) Llama a una función f con los argumentos args de acuerdo con una política de lanzamiento específica policy:
  • Si la bandera async se establece (es decir, policy &std::launch::async!=0), entonces async ejecuta el objeto llamable f en un nuevo hilo de ejecución (con todas las variables locales al hilo inicializadas) como si se hubieran generado por std::thread(std::forward<F>(f), std::forward<Args>(args)...), excepto que si la función f devuelve un valor o produce una excepción, éste se almacena en el estado compartido accesible a través del std::future que async devuelve al llamador.
  • Si la bandera deferred se establece (es decir, policy &std::launch::deferred!=0), entonces async convierte a f y a args... de la misma manera que si lo fuera mediante el constructor de std::thread, pero no genera un nuevo hilo de ejecución. En su lugar se realiza evaluación perezosa: la primera llamada a una función de espera sin sincronizar en el std::future que devolvió async al llamador ocasionará que se invoque a la copia de f (como un rvalue) con las copias de args... (también pasados como rvalues) en el hilo actual (que no tiene que ser el hilo que llamó originalmente a std::async). El resultado o excepción se ubica en el estado compartido asociado con el std::future y solamente entonces se deja listo. Todos los accesos posteriores al mismo std::future devolverán el resultado inmediatamente.
  • Si tanto la bandera std::launch::async como la bandera std::launch::deferred están establecidas en policy, depende de la implementación si se realiza una ejecución asíncrona o una evaluación perezosa.
  • Si ni la bandera std::launch::async ni la bandera std::launch::deferred están establecidas, ni ninguna otra bandera de una política definida por la implementación está establecida en policy, el comportamiento es indefinido.
(desde C++14)

En cualquier caso, la llamada a std::async se sincroniza-con (como se define en el orden de memoria (std::memory_order)) la llamada a f, y la finalización de f es secuenciada-antes de dejar el estado compartido listo. Si se escoge la política async, la finalización del hilo asociado se sincroniza-con el retorno exitoso de la primera función que está esperando al estado compartido, o con el retorno de la última función que libera el estado compartido, lo que suceda primero.

Contenido

[editar]Parámetros

f - Objeto que puede ser llamado (Callable) a llamar.
args... - Parámetros para pasar a f.
policy - Valor de máscara de bits, donde los bits individuales controlan los métodos de ejecución permitidos.
Bit Explicación
std::launch::async Habilita la evaluación asíncrona.
std::launch::deferred Habilita la evaluación perezosa.


Requisitos de tipo
-
Function, Args debe satisfacer los requisitos de MoveConstructible.

[editar]Valor de retorno

Un futuro (std::future) que se refiere al estado compartido creado por esta llamada a std::async.

[editar]Excepciones

Lanza std::system_error con la condición de error std::errc::resource_unavailable_try_again si la política de lanzamiento es igual a std::launch::async y la implementación no es capaz de iniciar un nuevo hilo (si la política es async|deferred o tiene bits adicionales establecidos, volverá a deferred o a las políticas definidas por la implementación, en este caso), o std::bad_alloc si no se puede asignar memoria para las estructuras de datos internas.

[editar]Notas

La implementación puede extender el comportamiento de la primera sobrecarga de std::async al habilitar bits adicionales (definidos por la implementación) en la política de inicio predeterminada.

Ejemplos de políticas de inicio definidas por la implementación son la política de sincronización (ejecutar inmediatamente, dentro de la llamada asíncrona) y la política de tareas (similar a la asíncrona, pero las variables locales al hilo no se borran).

Si el futuro (std::future) obtenido de std::async no se mueve o se vincula a una referencia, el destructor del std::future se bloqueará al final de la expresión completa hasta que se complete la operación asíncrona, esencialmente haciendo que código como el siguiente sea síncrono:

std::async(std::launch::async, []{ f();});// dtor del temporal espera a f() std::async(std::launch::async, []{ g();});// no comienza hasta que se complete f()

(ten en cuenta que los destructores de futuros std::future obtenidos por medios distintos de una llamada a std::async nunca se bloquean).

[editar]Ejemplo

#include <iostream>#include <vector>#include <algorithm>#include <numeric>#include <future>#include <string>#include <mutex>   std::mutex m;struct X {void foo(int i, conststd::string& str){std::lock_guard<std::mutex> lk(m);std::cout<< str <<' '<< i <<'\n';}void bar(conststd::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)returnstd::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<<"La suma es "<< parallel_sum(v.begin(), v.end())<<'\n';   X x;// Llama a (&x)->foo(42, "Hola") con la política por defecto:// puede imprimir "Hola 42" concurrentemente o diferir la ejecuciónauto a1 = std::async(&X::foo, &x, 42, "Hola");   // Llama a x.bar("mundo") con la política diferida// imprime "mundo" cuando se llama a a2.get() o a a2.wait()auto a2 = std::async(std::launch::deferred, &X::bar, x, "mundo");   // Llama a X()(43); con política asíncrona (async)// imprime "43" concurrentementeauto a3 = std::async(std::launch::async, X(), 43);   a2.wait();// imprime "mundo"std::cout<< a3.get()<<'\n';// imprime "53"   }// si a1 no ha terminado en este punto, el destructor de a1 aquí imprime "Hola 42"

Posible salida:

La suma es 10000 43 mundo 53 Hola 42

[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 2021 C++11 Tipo de retorno incorrecto y categoría de valor
de los argumentos no son claros en el caso
diferido
Tipo de retorno corregido y se clarificó que se utilizan
rvalues.
close