boost::asio::spawn 是做什么的?
What does boost::asio::spawn do?
我无法在脑海中形成控制流如何随 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 连接,当特定实例挂起等待 async_foo
完成时,如何调用 my_coroutine
的其他实例?
简而言之:
- When
spawn()
is invoked, Boost.Asio performs some setup work and then will use a strand
to dispatch()
内部处理程序使用用户提供的函数作为入口点创建协程。在某些情况下,内部处理程序可以在对 spawn()
的调用中被调用,而其他时候它将被发布到 io_service
以进行延迟调用。
- 协程被挂起,直到操作完成并调用完成处理程序,
io_service
被销毁,或者 Boost.Asio 检测到协程已被挂起且无法恢复,此时 Boost.Asio 将销毁协程。
如上所述,当 spawn()
被调用时,Boost.Asio 执行一些设置工作,然后将使用 strand
到 dispatch()
创建协程的内部处理程序使用用户提供的功能作为入口点。当 yield_context
对象作为处理程序传递给异步操作时,Boost.Asio 将在使用完成处理程序启动异步操作后立即 yield 将复制结果和 恢复协程。前面提到的 strand 由协程拥有,用于保证 yield 发生在 resume 之前。让我们考虑一个简单的例子 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.
我无法在脑海中形成控制流如何随 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 连接,当特定实例挂起等待 async_foo
完成时,如何调用 my_coroutine
的其他实例?
简而言之:
- When
spawn()
is invoked, Boost.Asio performs some setup work and then will use astrand
todispatch()
内部处理程序使用用户提供的函数作为入口点创建协程。在某些情况下,内部处理程序可以在对spawn()
的调用中被调用,而其他时候它将被发布到io_service
以进行延迟调用。 - 协程被挂起,直到操作完成并调用完成处理程序,
io_service
被销毁,或者 Boost.Asio 检测到协程已被挂起且无法恢复,此时 Boost.Asio 将销毁协程。
如上所述,当 spawn()
被调用时,Boost.Asio 执行一些设置工作,然后将使用 strand
到 dispatch()
创建协程的内部处理程序使用用户提供的功能作为入口点。当 yield_context
对象作为处理程序传递给异步操作时,Boost.Asio 将在使用完成处理程序启动异步操作后立即 yield 将复制结果和 恢复协程。前面提到的 strand 由协程拥有,用于保证 yield 发生在 resume 之前。让我们考虑一个简单的例子 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.