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.

21
demandé sur David Haim 2018-07-21 12:31:22

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>)> est future<R2>, pour certains types R2, la fonction renvoie future<R2>. Sinon, la fonction renvoie future<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 un future<R> aurait été future<future<R>>. Cette règle évite de tels objets futurs imbriqués. Le type de f2 ci-dessous est future<int> et pas future<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 type std::future_error, avec une condition d'erreur de std::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.

2
répondu Yakk - Adam Nevraumont 2018-08-30 17:06:10