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
Défini dans l'en-tête <future>
template < class F, class ... Args >
std:: future < /* voir ci-dessous */ > async ( F && f, Args && ... args ) ;
(1) (depuis C++11)
template < class F, class ... Args >

std:: future < /* voir ci-dessous */ > async ( std:: launch policy,

F && f, Args && ... args ) ;
(2) (depuis C++11)

Le modèle de fonction std::async exécute la fonction f de manière asynchrone (potentiellement dans un thread séparé qui pourrait faire partie d'un pool de threads) et retourne un std::future qui contiendra éventuellement le résultat de cet appel de fonction.

1) Se comporte comme si (2) était appelé avec policy étant std:: launch :: async | std:: launch :: deferred .
2) Appelle une fonction f avec les arguments args selon une politique de lancement spécifique policy (voir ci-dessous ).

Le type de retour de std::async est std:: future < V > , où V est :

typename std:: result_of < typename std:: decay < F > :: type (
typename std:: decay < Args > :: type ... ) > :: type .

(jusqu'à C++17)

std:: invoke_result_t < std:: decay_t < F > , std:: decay_t < Args > ... > .

(depuis C++17)


Si l'une des conditions suivantes est satisfaite, le programme est mal formé :

(jusqu'en C++20)

Si l'une des conditions suivantes est false , le programme est mal formé :

(depuis C++20)

L'appel à std::async se synchronise avec l'appel à f , et l'achèvement de f est séquencé avant la préparation de l'état partagé.

Table des matières

Paramètres

f - Callable objet à appeler
args - paramètres à passer à f
policy - valeur de masque de bits, où les bits individuels contrôlent les méthodes d'exécution autorisées

Valeur de retour

std::future se référant à l'état partagé créé par cet appel à std::async .

Politiques de lancement

Invocation asynchrone

Si l'indicateur async est défini, c'est-à-dire ( policy & std:: launch :: async ) ! = 0 , alors std::async appelle

INVOKE ( decay-copy ( std:: forward < F > ( f ) ) ,
decay-copy ( std:: forward < Args > ( args ) ) ... )

(jusqu'à C++23)

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

(depuis C++23)

comme si dans un nouveau thread d'exécution représenté par un std::thread objet.

Les appels à decay-copy sont évalués dans le thread actuel.

(jusqu'à C++23)

Les valeurs produites par auto sont matérialisées dans le thread actuel.

(depuis C++23)

Si la fonction f retourne une valeur ou lance une exception, elle est stockée dans l'état partagé accessible via le std::future que std::async retourne à l'appelant.

Invocation différée

Si l'indicateur deferred est activé (c'est-à-dire ( policy & std:: launch :: deferred ) ! = 0 ), alors std::async stocke

decay-copy ( std:: forward < F > ( f ) ) et decay-copy ( std:: forward < Args > ( args ) ) ... dans l'état partagé.

(jusqu'à C++23)

auto ( std:: forward < F > ( f ) ) et auto ( std:: forward < Args > ( args ) ) ... dans l'état partagé.

(depuis C++23)

Évaluation paresseuse est effectuée :

  • Le premier appel à une fonction d'attente non temporisée sur le std::future que std::async a retourné à l'appelant évaluera INVOKE ( std :: move ( g ) , std :: move ( xyz ) ) dans le thread qui a appelé la fonction d'attente (qui ne doit pas nécessairement être le thread qui a initialement appelé std::async ), où
(jusqu'à C++23)
(depuis C++23)
  • Le résultat ou l'exception est placé dans l'état partagé associé au std::future retourné, et c'est seulement alors qu'il devient prêt. Tous les accès ultérieurs au même std::future retourneront le résultat immédiatement.

Autres politiques

Si ni std::launch::async ni std::launch::deferred , ni aucun indicateur de politique défini par l'implémentation n'est défini dans policy , le comportement est indéfini.

Sélection de politique

Si plus d'un indicateur est défini, il est défini par l'implémentation quelle politique est sélectionnée. Pour la valeur par défaut (à la fois les std::launch::async et std::launch::deferred sont définis dans policy ), la norme recommande (mais n'impose pas) d'utiliser la concurrence disponible et de différer toute tâche supplémentaire.

Si la politique std::launch::async est choisie,

  • un appel à une fonction d'attente sur un objet de retour asynchrone qui partage l'état partagé créé par cet std::async appel bloque jusqu'à ce que le thread associé ait terminé, comme s'il était joint, ou jusqu'à l'expiration du délai ; et
  • la terminaison du thread associé synchronizes-with le retour réussi de la première fonction qui attend sur l'état partagé, ou avec le retour de la dernière fonction qui libère l'état partagé, selon celui qui survient en premier.

Exceptions

Lance

Notes

L'implémentation peut étendre le comportement de la première surcharge de std::async en activant des bits supplémentaires (définis par l'implémentation) dans la politique de lancement par défaut.

Exemples de politiques d'exécution définies par l'implémentation incluent la politique synchrone (exécution immédiate, dans l'appel std::async ) et la politique de tâche (similaire à std::async , mais les variables locales au thread ne sont pas réinitialisées)

Si le std::future obtenu à partir de std::async n'est pas déplacé ou lié à une référence, le destructeur du std::future bloquera à la fin de l'expression complète jusqu'à ce que l'opération asynchrone se termine, rendant essentiellement synchrone un code tel que le suivant :

std::async(std::launch::async, []{ f(); }); // le destructeur du temporaire attend f()
std::async(std::launch::async, []{ g(); }); // ne démarre qu'après l'achèvement de f()

Notez que les destructeurs des std::future obtenus par d'autres moyens qu'un appel à std::async ne bloquent jamais.

Exemple

#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;
    // Appelle (&x)->foo(42, "Hello") avec la politique par défaut :
    // peut afficher "Hello 42" concurremment ou différer l'exécution
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // Appelle x.bar("world!") avec politique différée
    // affiche "world!" quand a2.get() ou a2.wait() est appelé
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // Appelle X()(43); avec politique asynchrone
    // affiche "43" concurremment
    auto a3 = std::async(std::launch::async, X(), 43);
    a2.wait();                     // affiche "world!"
    std::cout << a3.get() << '\n'; // affiche "53"
} // si a1 n'est pas terminé à ce stade, le destructeur de a1 affiche "Hello 42" ici

Sortie possible :

The sum is 10000
43
world!
53
Hello 42

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement corrigé
LWG 2021 C++11 type de retour incorrect et catégorie de valeur
des arguments non claire dans le cas différé
type de retour corrigé et
clarification que les rvalues sont utilisées
LWG 2078 C++11 il n'était pas clair si std::system_error
pouvait être levée si policy spécifie d'autres
politiques de lancement en plus de std::launch::async
ne peut être levée que si
policy == std:: launch :: async
LWG 2100 C++11 les fonctions d'attente temporisée ne pouvaient pas expirer
si la politique std::launch::async est utilisée
autorisé
LWG 2120 C++11 le comportement n'était pas clair si aucune politique
standard ou définie par l'implémentation n'est définie
le comportement est
indéfini dans ce cas
LWG 2186 C++11 il n'était pas clair comment la valeur retournée et l'
exception levée par l'évaluation paresseuse sont gérées
elles sont stockées dans
l'état partagé
LWG 2752 C++11 std::async pourrait ne pas lever std::bad_alloc si la
mémoire pour les structures de données internes ne peut être allouée
lève
LWG 3476 C++20 (les types dégradés de) F et les types d'arguments
étaient directement requis d'être constructibles par déplacement
ces exigences supprimées [1]
  1. La constructibilité par déplacement est déjà indirectement requise par std::is_constructible_v .

Voir aussi

(C++11)
attend une valeur définie de manière asynchrone
(modèle de classe)
Documentation C++ pour Bibliothèque de support d'exécution