Can I use a stackful coroutine as the wait handler of a steady_timer which is defined inside the very stackful coroutine?

寵の児 提交于 2019-11-30 20:53:11

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:

  • control exits the block specified by Work() via either a return, reaching end of function, or an exception unwinding the stack.
  • The associated 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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!