基于栈的协程

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.

results matching ""

    No results matching ""