Namespaces
Variants

std:: async

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
async
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
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,

F && f, Args && ... args ) ;
(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.

1) Se comporta como si (2) fuera llamado con policy siendo std:: launch :: async | std:: launch :: deferred .
2) Llama a una función f con argumentos args de acuerdo con una política de lanzamiento específica policy (ver abajo ).

El tipo de retorno de std::async es std:: future < V > , donde V es:

typename std:: result_of < typename std:: decay < F > :: type (
typename std:: decay < Args > :: type ... ) > :: 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 ) ) ,
decay-copy ( std:: forward < Args > ( args ) ) ... )

(hasta C++23)

std:: invoke ( auto ( std:: forward < F > ( f ) ) ,
auto ( std:: forward < Args > ( args ) ) ... )

(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::async devolvió 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ó a std::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::async llamada 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

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]
  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