我无法形成关于控制流如何与spawn发生的精神图景.
>当我调用spawn(io_service,my_coroutine)时,它是否会向io_service队列添加一个新的处理程序来包装对my_coroutine的调用?
>当在协同程序中我调用异步函数传递我的yield_context时,是否挂起协同程序直到异步操作完成?
- void my_coroutine(yield_context yield)
- {
- ...
- async_foo(params ...,yield);
- ... // control comes here only once the async_foo operation completes
- }
我不明白的是我们如何避免等待.假设my_coroutine服务于TCP连接,在特定实例挂起时,如何调用my_coroutine的其他实例,等待async_foo完成?
解决方法
简而言之:
>当调用spawn()
时,Boost.Asio执行一些设置工作,然后将使用strand
到dispatch()
内部处理程序,该处理程序使用用户提供的函数作为入口点创建协同程序.在某些条件下,可以在对spawn()的调用中调用内部处理程序,有时将其发布到io_service以进行延迟调用.
>协程暂停,直到操作完成并调用完成处理程序,io_service被销毁,或者Boost.Asio检测到协程已被挂起而无法恢复它,此时Boost.Asio将破坏协同程序.
如上所述,当调用spawn()时,然后使用strand来调度()内部处理程序,该处理程序使用用户提供的函数作为入口点创建协同程序.当yield_context对象作为处理程序传递给异步操作时,Boost.Asio将在使用完成处理程序启动异步操作后立即生成,该处理程序将复制结果并恢复协程.前面提到的链是由coroutine所有,用于保证在恢复之前产生的产量.让我们考虑一个简单的例子demonstrating spawn():
- #include <iostream>
- #include <boost/asio.hpp>
- #include <boost/asio/spawn.hpp>
- boost::asio::io_service io_service;
- void other_work()
- {
- std::cout << "Other work" << std::endl;
- }
- void my_work(boost::asio::yield_context yield_context)
- {
- // Add more work to the io_service.
- io_service.post(&other_work);
- // Wait on a timer within the coroutine.
- boost::asio::deadline_timer timer(io_service);
- timer.expires_from_now(boost::posix_time::seconds(1));
- std::cout << "Start wait" << std::endl;
- timer.async_wait(yield_context);
- std::cout << "Woke up" << std::endl;
- }
- int main ()
- {
- boost::asio::spawn(io_service,&my_work);
- io_service.run();
- }
以上示例输出:
- Start wait
- Other work
- Woke up
这是尝试说明示例的执行.路径|表示活动堆栈,:表示挂起的堆栈,箭头用于表示控制转移:
- boost::asio::io_service io_service;
- boost::asio::spawn(io_service,&my_work);
- `-- dispatch a coroutine creator
- into the io_service.
- io_service.run();
- |-- invoke the coroutine creator
- | handler.
- | |-- create and jump into
- | | into coroutine ----> my_work()
- : : |-- post &other_work onto
- : : | the io_service
- : : |-- create timer
- : : |-- set timer expiration
- : : |-- cout << "Start wait" << endl;
- : : |-- 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 : :
- | &other_work and async_wait) : :
- |-- invoke other_work() : :
- | `-- cout << "Other work" : :
- | << endl; : :
- |-- io_service still 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 << "Woke up." << endl;
- : : |-- exiting my_work block,timer is
- : : | destroyed.
- | `-- return <---- `-- coroutine done,yielding
- `-- no outstanding work in
- io_service,return.