le comportement de std::async(std::lancement::différé) + std::future::alors
L'idée derrière un futur différé (réalisé uniquement en appelant std::async
avec std::launch::deferred
flag) est que le rappel n'est appelé que lorsque quelqu'un essaie d'attendre ou de tirer la valeur futuriste ou l'exception du futur. d'ici là, le rappel n'est pas exécuté.
Que se passe-t-il si j'attache une continuation à un futur différé avec std::future::then
? le futur différé est perdu (then
invalide le futur) et un nouveau futur est retourné à la place.
Dans ce cas, selon la norme, ce qui devrait arriver? le nouvel avenir est-il aussi un avenir différé? serait-il juste de blocage? cette question n'est pas abordée dans la documentation la plus récente.
1 réponses
, à mon avis, semble être un bug dans pg. Ou au moins un piège sous-documenté.
Voici le texte du TS:
2.3 [terme.unique_future] / 6-10
template <class F> see below then(F&& func);
Nécessite:
INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.
Effets:
La fonction crée un état partagé associé à l'objet futur renvoyé. En outre,
Lorsque l'état partagé de l'objet est prêt, la continuation
INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))
est appelée sur un thread d'exécution avec l'appel àDECAY_COPY()
en cours d'évaluation dans le thread qui a appelé alors.Toute valeur renvoyée par la suite est stockée comme résultat dans l'état partagé du futur résultant. Toute exception propagée à partir de l'exécution de la continuation est stockée comme résultat exceptionnel dans l'état partagé du futur résultant.
Renvoie:
Lorsque
result_of_t<decay_t<F>(future<R>)>
estfuture<R2>
, pour certains types R2, la fonction renvoiefuture<R2>
. Sinon, la fonction renvoiefuture<result_of_t<decay_t<F>(future<R>)>>
. [Note: la règle ci-dessus est appelée déballage implicite. Sans cette règle, le type de retour de prendre alors un appel retournant unfuture<R>
aurait étéfuture<future<R>>
. Cette règle évite de tels objets futurs imbriqués. Le type def2
ci-dessous estfuture<int>
et pasfuture<future<int>>
:[ Exemple:
future<int> f1 = g(); future<int> f2 = f1.then([](future<int> f) { future<int> f3 = h(); return f3; });
- exemple de fin]
- note de fin]
Postconditions:
valid() == false
sur le futur original.valid() == true
sur le futur est revenu à partir de là. [ Remarque: En cas de déballage implicite, la validité du futur renvoyé par thenfunc ne peut être établie qu'après l'achèvement de la continuation. S'il n'est pas valide, le futur résultant devient prêt à l'exception du typestd::future_error
, avec une condition d'erreur destd::future_errc::broken_promise
. - note de fin]
Il n'y a pas de cas particulier pour une tâche future différée. Si cette tâche future différée n'est pas prête avant d'appeler .then
, Il n'y a aucun moyen pour qu'elle devienne prête, donc il n'y a aucun moyen pour la copie cariée de func
à invoquer.
Le texte de shared_future
est similaire; là, vous pouvez toujours faire en sorte que le shared_future
soit prêt après avoir appelé .then
cependant.
Si cela est prévu; que .then
sur un avenir unique différé non prêt entraînera une valeur de retour d'un {[24] } qui ne peut jamais être prêt - cela devrait être explicite dans la norme TS/. Si cela n'est pas prévu, le texte standard doit être modifié.
Notez que ces modifications n'apparaissent pas dans le n4762 projet de norme publié en 2018.
Je ne sais pas comment la norme devrait résoudre ce problème; la sémantique .then
est raisonnable pour un shared_future
mais pas pour un future
, et une sémantique différente serait surprenante.