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:
Work()
via un return
, une fin de fonction ou une exception vidée de la stack. 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.