std:: async
|
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,
|
(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.
Le type de retour de
std::async
est
std::
future
<
V
>
, où
V
est :
|
typename
std::
result_of
<
typename
std::
decay
<
F
>
::
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
)
)
,
|
(jusqu'à C++23) |
|
std::
invoke
(
auto
(
std::
forward
<
F
>
(
f
)
)
,
|
(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::asynca 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::asyncappel 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
- std::bad_alloc , si la mémoire pour les structures de données internes ne peut pas être allouée, ou
-
std::system_error
avec la condition d'erreur
std::errc::resource_unavailable_try_again
, si
policy
==
std::
launch
::
async
et que l'implémentation est incapable de démarrer un nouveau thread.
- Si policy est std:: launch :: async | std:: launch :: deferred ou a des bits supplémentaires définis, il basculera vers l'invocation différée ou les politiques définies par l'implémentation dans ce cas.
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] |
- ↑ 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
|
|