asio学习笔记7

http://www.godebug.org/index.php/archives/74/

Thu

asio学习笔记7


asio中用到了两种coroutine,一个是asio作者自己写的stackless coroutine,一个是封装了Boost.Coroutine的spawn,Boost.Coroutine是boost库中的一个stackful coroutine。其实这两个的主要区别我觉得就是stackless的不能使用局部变量,但是速度较快;stackful的可以使用局部变量,但是速度可能不如stackless的。

首先说一下coroutine是个什么玩意,其实很多语言中都有这个东西,个人感觉这个玩意就像hyq童鞋说的那样,就是个带状态的函数,每次调用执行不同的功能。先上一下stackless的coroutine的简单示例:

#include <iostream>
#include <boost/asio/yield.hpp>

int foo(boost::asio::coroutine& ct)
{
    std::cout << "before reenter" << std::endl;

    reenter(ct)
    {
        std::cout << "before yield1" << std::endl;
        yield std::cout << "yield1" << std::endl;
        std::cout << "before yield2" << std::endl;
        yield return 1;
    }

    std::cout << "after reenter" << std::endl;
    return 2;
}

int main(int argc, char* argv[])
{
    boost::asio::coroutine ct;
    while (!ct.is_complete())
    {
        int ret = foo(ct);
        std::cout << "return:" << ret << std::endl;
    }
    return 0;
}

运行结果:
20140218110755.png

简单来说就是首先会执行reenter之前的代码(打印before reenter),当函数运行到reenter范围内的时候,第一次会执行第一个yield之前的代码(打印before yield1)和yield关键词之后跟的那个语句(打印 yield1),然后直接跳出reenter范围执行之后的代码(打印after reenter和return 2);第二次调用时进入reenter后则会直接从第一个yield下面开始执行,执行到第二个yield结束,因为yield后面接的是一个return语句,所以reenter范围后面的代码没有执行;当没有yield可以继续执行的时候,就不再进入reenter了。

灰常简单,其实就是个switch case,我都觉得自己用switch case实现个肯定不比这个差。不过这几天学习asio下来发现,asio本身根本就没啥可学习的高级的东西,都是在学他的思想,虽然只是这么简单的一段代码,换个思维方式可能就会有很大作用,一般在异步程序中使用coroutine就是为了少写一些回调。如果一个协议里面要有顺序的读写几十次的话,对于同步的操作来说很简单,一路按照协议read、write、read、write下来就行了,但是异步的就不行了,你必须在上一个read或者write完成的handler中发起下一次的read或者write,协议稍微一复杂,回调函数就会多得让你恶心,这个时候coroutine就派上用场了,只需要一个回调函数,只要不停的调用就好了,函数会自动的按照你写得yield的顺序执行相应的代码,让代码看起来就像是同步的一样。上一下代码,还是异步的echo server:

// asio_sample.cpp : 定义控制台应用程序的入口点。
//

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/asio/yield.hpp>
#include <iostream>

boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 1234);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);

char data[1024];

void handle(boost::asio::coroutine ct,boost::asio::ip::tcp::socket* sock,
    const boost::system::error_code& error,size_t bytes_transferred)
{
    if (error)
    {
        std::cout << "read发生错误:" << error.message() << std::endl;
        delete sock;
        return;
    }

    reenter(ct)
    {
        yield boost::asio::async_write(*sock, boost::asio::buffer(data, bytes_transferred),
            boost::bind(handle,ct, sock,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));

        yield sock->async_read_some(boost::asio::buffer(data),
            boost::bind(handle, boost::asio::coroutine(),sock,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

}

void session(boost::asio::ip::tcp::socket* sock,
    const boost::system::error_code& error)
{
    if (error)
    {
        delete sock;
    }
    else
    {
        std::cout << "有客户端连接" << std::endl;

        sock->async_read_some(boost::asio::buffer(data),
            boost::bind(handle, boost::asio::coroutine(),sock,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

    boost::asio::ip::tcp::socket* s = new boost::asio::ip::tcp::socket(ios);
    acceptor.async_accept(*s, boost::bind(session, s,
        boost::asio::placeholders::error));
}

int main(int argc, char* argv[])
{
    boost::asio::ip::tcp::socket* s = new boost::asio::ip::tcp::socket(ios);
    acceptor.async_accept(*s, boost::bind(session, s, boost::asio::placeholders::error));

    ios.run();
    return 0;
}

运行结果就不贴了,因为功能跟asio学习笔记5中的那个一模一样.这里每次收到收据都要把它写回去,本来需要两个handler,但是用了yiled之后就可以只需要一个了。

另外需要说一下boost::asio::coroutine可以作为一个基类,然后在子类的函数中使用reenter(this)就可以了,但是我还是比较喜欢把它作为一个成员变量或者参数,这个看个人喜好了,asio的http server4示例就是用stackless coroutine写的,想研究的童鞋可以看看去。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值