asio学习笔记2

来源:互联网 发布:ubuntu下移动文件夹 编辑:程序博客网 时间:2024/05/21 15:00

asio学习笔记2

继续写。。今天的讨论的主题是io_service::run函数什么时候会退出。
先上代码:

#include <boost/asio.hpp>#include <boost/thread.hpp>#include <iostream>int num = 0;void foo(){    std::cout << "hello " << ++num << std::endl;}int main(int argc, char* argv[]){    boost::asio::io_service ios;    for (int i = 0; i < 10; ++i)    {        ios.post(foo);    }    std::cout << "执行run之前" << std::endl;    ios.run();    std::cout << "run执行完毕" << std::endl;    return 0;}

运行结果:
20140218102422.jpg
结果跟猜想的一样,其实所有事件都不过是在run函数中运行的,只要还有事件没完成,也没有出错,run函数是不会退出的。这是肯定的嘛,你又不开线程,又不想在任何地方阻塞本线程,本来就是不合理的。

如果你想让完成一个事件返回一次,可续选择用run_one,这样的话只要完成一个事件就会返回一次,而不是所有的都完成了才返回。使用run_one的话需要用配合stopped函数来判断是否所有时间都已经执行完了。其实run函数与下面的代码是一样的效果:

while (!ios.stopped()){    ios.run_one();}

另外当所执行的事件出错时,run函数也会退出或抛出异常。run函数和run_one函数都有两个重载,没有参数的run或run_one在遇到异常时自己也会会抛出boost::system::system_error异常,加了boost::system::error_code&参数的版本则会将错误信息写入该参数然后返回。不过我还一直没遇到过run函数抛出异常或者出错的情况,可能是用的太少了。

既然只要还有“任务”,run就不会退出,个人认为一个好的设计应该一直让我们的发动机有事情可做,一直到做完所有的事情然后退出,如下面的代码:

#include <boost/bind.hpp>#include <boost/asio.hpp>#include <boost/filesystem.hpp>#include <iostream>void async_dir(boost::asio::io_service& io, boost::filesystem::directory_iterator& di){    if (di == boost::filesystem::directory_iterator())    {        return;    }    if (boost::filesystem::is_directory(di->path()))    {        boost::system::error_code ec;        boost::filesystem::directory_iterator sub_di(di->path(),ec);        if (!ec)        {            io.post(boost::bind(&async_dir, boost::ref(io), sub_di));        }        else        {            std::cout << "遍历目录 " << di->path() << "出错,错误原因为:" << ec.message() << std::endl;        }    }    std::cout << di->path() << std::endl;    boost::system::error_code ec;    ++di;    io.post(boost::bind(&async_dir, boost::ref(io), di));}int main(int argc, char* argv[]){    boost::asio::io_service io;    boost::filesystem::path p("C:\\");    boost::system::error_code ec;    boost::filesystem::directory_iterator di(p,ec);    int num = 0;    if (!ec)    {        io.post(boost::bind(&async_dir, boost::ref(io), di));    }    else    {        std::cout << "遍历目录 " << p << "出错,错误原因为:" << ec.message() << std::endl;    }    io.run();    return 0;}

这个是avplayer社区的microcai提出的一个异步递归的思想,不过他实现的那个是不会并行进行递归的,还用了coroutine,而且他第三擅长的事就是把简单的东西写的让人看不懂(我不说写的复杂),不熟悉的人可能看不明白,我也是看了jackarain的文章才搞明白的。这里就是在主函数中只post了一次,当函数完成或找到子文件夹时就再次调用post给发动机添加任务,直到所有的任务都已完成,就无需添加任务了,run函数自然就退出了。

虽然最好的做法是一直让发动机有事可做而不会退出,可是有的时候可能并不能做的这么完善,但是又不想让run退出,这时候你就需要boost::asio::io_service::work来帮忙,这个类的作用就是让io_service一直处于有事可做的状态而不会从run函数中退出,这样就避免了我们自己写循环重复调用run函数。当work析构而且没有任务的时候,run就会返回,测试代码如下:

#include <boost/asio.hpp>#include <boost/thread.hpp>#include <boost/thread.hpp>#include <iostream>boost::asio::io_service::work* work = NULL;void foo(){    std::cout << "hello" << std::endl;}void thd_fun(){    std::getchar();    delete work;}int main(int argc, char* argv[]){    boost::asio::io_service ios;    ios.post(foo);    work = new boost::asio::io_service::work(ios);    boost::thread thd(thd_fun);    boost::system::error_code ec;    std::cout << "before run" << std::endl;    ios.run(ec);    std::cout << "after run" << std::endl;    return 0;}

今天就先写这点,明天开始写几个基本的网络函数。


0 0
原创粉丝点击