基于栈的协程
spawn()是对基于栈实现的用户协程的高度抽象。它是基于Boost.Coroutine库的。spawn()函数允许程序像同步逻辑那样使用异步逻辑,如下所示:
asio::spawn(my_strand, do_echo);
//...
void do_echo(asio::yield_contex yield)
{
try
{
char data[128];
for(;;)
{
std::size_t length = my_soscket.async_read_some(asio::buffer(data),yield);
}
}
catch(std::exception& e)
{
//...
}
}
spawn()函数的第一个参数可以是strand,io_service或者是完成事件回调,这个参数决定了是在哪个协程执行上下文。举个栗子,一个服务器的每一个客户端包含了多个协程,它们应该在同一个strand中,不需要你去显式地同步它们。
第二个参数是一个包含特殊符号的函数对象:
void coroutine(asio::yield_context yield);
该符号保证了代码在协程内部执行。参数yield会替代异步操作的完成事件回调,比如:
std::size_t length =
my_socket.async_read_som(
asio::buffer(data), yield);
这段代码开始了异步操作,然后暂停了这个协程。它会在异步操作完成后自动调用。(译者注:由于没有操作系统层的优化,该协程应该也是基于epoll()这样类似的模型,轮询的成本并不会比线程切换低,更比不上异步事件)
当回调函数为如下形式时:
void handler(asio::error_code ec, result_type result);
这个函数原型返回result_type的值,在 async_read_some中返回 size_t,如果操作失败,它会抛出 system_error类型的异常,这是由 error_code转化来的。
当回调函数为如下形式时:
void handler(asio::error_code ec);
函数原型返回空值。协程会抛出system_error类型的异常。
当你不想使用抛出异常这样的形式,而想要收集异常数据,使用yield_context:
asio::error_code ec;
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield[ec]);
注意:如果你使用Handler类型作为spawn的第二个参数,那么你需要使用如下的形式:
void coroutine(asio::basic_yield_context<Handler> yield);
参见:
spawn, yield_context, basic_yield_context, Spawn example (C++03), Spawn example (C++11), Stackless Coroutines.