Puis-je utiliser une coroutine empilée en tant que gestionnaire d’attente d’un timer_stable défini dans la coroutine très empilée?

Puis-je utiliser la coroutine empilée et boost::asio::steady_timer::async_wait de la manière suivante? Le fait est que (si j’ai bien compris, je ne suis pas sûr) pendant l’attente, le timer variable locale n’est pas sur la stack et donc inaccessible. Alors, le rappel peut-il se dérouler normalement? (Pour votre information, cela fonctionne bien sur mon Mac utilisant Clang ++ 5.0.)

 boost::asio::io_service io; void Work(boost::asio::yield_context yield) { boost::asio::steady_timer timer(io); timer.expires_from_now(std::chrono::seconds(5)); timer.async_wait(yield); cout << "Woke up." << endl; } int main() { boost::asio::spawn(io, Work); io.run(); return 0; } 

Je pense que cela vaut la peine de comparer cette question: boost asio delay_timer

Oui, il est prudent de passer boost::asio::yield_context à un object ayant une durée de stockage automatique dans la même coroutine.

Boost.Coroutine utilise Boost.Context pour effectuer une commutation de contexte. Boost.Context fournit un moyen de suspendre le chemin d’exécution actuel, en préservant la stack (y compris les variables locales telles que le timer Work() ), et en contrôlant le transfert de l’exécution, permettant au même thread de s’exécuter avec une stack différente. Par conséquent, avec l’object boost::asio::steady_timer ayant une durée de stockage automatique, sa durée de vie prendra fin lorsque:

  • control quitte le bloc spécifié par Work() via un return , une fin de fonction ou une exception vidée de la stack.
  • Le io_service associé est détruit. Les gestionnaires internes conservent la propriété partagée de la coroutine et, lorsque le service io_service est détruit, tous les gestionnaires associés sont également détruits. Cette destruction obligera Boost.Coroutine à forcer le stack de chaque coroutine à se dérouler.

Lorsque boost::asio::spawn() est appelé, Boost.Asio effectue un travail de configuration puis envoie un gestionnaire interne qui créera un coroutine en utilisant la fonction fournie par l’utilisateur comme point d’entrée. Lorsque l’object yield_context est passé en tant que gestionnaire à des opérations asynchrones, Boost.Asio cédera immédiatement après le lancement de l’opération asynchrone avec un gestionnaire d’achèvement qui copie les résultats et reprend la coroutine. Un strand appartenant à la coroutine est utilisé pour garantir le rendement avant la reprise . Voici une tentative pour illustrer l’exécution de l’exemple de code:

 boost::asio::io_service io_service; boost::asio::spawn(io_service, &Work); `-- dispatch a coroutine creator into the io_service. io_service.run(); |-- invoke the coroutine creator | handler. | |-- create and jump into | | into coroutine ----> Work() : : |-- timer created : : |-- setting timer expiration : : |-- timer.async_wait(yield) : : | |-- create error_code on stack : : | |-- initiate async_wait operation, : : | | passing in completion handler that : : | | will resume the coroutine | `-- return <---- | |-- yield |-- io_service has work (the : : | async_wait operation) : : | ...async wait completes... : : |-- invoke completion handler : : | |-- copies error_code : : | | provided by service : : | | into the one on the : : | | coroutine stack : : | |-- resume ----> | `-- return error code : : |-- cout << "Waked up." << endl; : : |-- exiting Work() block, timer is : : | destroyed. | `-- return <---- `-- coroutine done, yielding `-- no outstanding work in io_service, return. 

oui – ça devrait marcher. boost :: asio :: steady_timer timer (io) enregistre le timer sur le service io.