Can I use stackful coroutine and boost::asio::steady_timer::async_wait
in the following way?
The point is that (my understanding, not sure) during waiting, loca
Yes, it is safe to pass boost::asio::yield_context
to an object that has automatic storage duration within the same coroutine.
Boost.Coroutine uses Boost.Context to perform context switching. Boost.Context provides a means to suspend the current execution path, preserving the stack (including local variables such as Work()
's timer
), and transfer execution control, allowing the same thread to run with a different stack. Hence, with the boost::asio::steady_timer
object having automatic storage duration, its lifespan will end when either:
Work()
via either a return
, reaching end of function, or an exception unwinding the stack.io_service
is destroyed. Internal handlers maintain shared ownership of the coroutine, and when the io_service
is destroyed, all associated handlers are also destroyed. This destruction will cause Boost.Coroutine to force each coroutine's stack to unwind.When boost::asio::spawn() is invoked, Boost.Asio performs some setup work and then will dispatch() an internal handler that will create a coroutine using the user provided function as an entry point. When the yield_context
object is passed as a handler to asynchronous operations, Boost.Asio will yield immediately after initiating the asynchronous operation with a completion handler that will copy results and resume the coroutine. A strand owned by the coroutine is used to guarantee the yield occurs before resume. Here is an attempt to illustrate the execution of the example 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.
yes - it should work. boost::asio::steady_timer timer(io) registers the timer on the io-service.