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

后端 未结 2 1127
眼角桃花
眼角桃花 2021-01-05 10:54

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

相关标签:
2条回答
  • 2021-01-05 11:49

    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.
    
    0 讨论(0)
  • 2021-01-05 11:49

    yes - it should work. boost::asio::steady_timer timer(io) registers the timer on the io-service.

    0 讨论(0)
提交回复
热议问题