Boost-asio之二

    上一篇介绍了Boost.Asio的一些特性,但是相对抽象和离散,这篇博客从Boost.Asio的基础知识一步步深入,读完之后对Boost.Asio会有全面的了解和掌握。Boost.Asio通过采用C++以及Boost库的语法特性,提供跨平台的异步网络IO能力。因此使用Boost.Asio需要基本的网络知识,C++、Boost知识。

        io_service是Boost.Asio的核心类,run()方法是它的重要方法之一,后续会陆续介绍到其dispatch,post,stop,reset等重要方法。run()方法的作用是阻塞程序直到所有的工作都完成,所有的handler都dispatch了;或者当调用stop方法时,run()方法也会不再阻塞下去。下面是一个说明run()方法的示例程序:

[cpp] view plain copy print ?
  1. #include <boost/asio.hpp>   
  2. #include <iostream>   
  3.   
  4. int main( int argc, char * argv[] )  
  5. {  
  6.     boost::asio::io_service io_service;  
  7.   
  8.     io_service.run();  
  9.   
  10.     std::cout << "Do you reckon this line displays?" << std::endl;  
  11.   
  12.     return 0;  
  13. }  
在Linux下在安装完Boost后,采用g++ 1a.cpp -o 1a -lboost_system进行编译(Boost.Asio会调用boost_system库的内容,所以需要指定链接内容,涉及到线程和多线程时,则分别要做如下指定 -pthread -lboost_thread-mt)。运行可执行文件,我们发现会有输出,这是因为没有给io_service添加任务,它自然就结束了,不会阻塞。

        通常我们不希望程序自动退出,因为可能还有其它任务需要处理,更多的时候希望控制程序何时退出,Boost.Asio考虑到了这点,看下面的例子:

[cpp] view plain copy print ?
  1. #include <boost/asio.hpp>   
  2. #include <iostream>   
  3.   
  4. int main( int argc, char * argv[] )  
  5. {  
  6.     boost::asio::io_service io_service;  
  7.     boost::asio::io_service::work work( io_service );  
  8.   
  9.     io_service.run();  
  10.   
  11.     std::cout << "Do you reckon this line displays?" << std::endl;  
  12.   
  13.     return 0;  
  14. }  
运行上面的例子,我们发现程序没有输出也不退出,在按Ctrl+C后程序才会终止。这主要是因为我们给了io_service工作---work,它在没有完成工作的情况时是不会退出的,在io_service.run()从io_service中删除work,程序就退出了。如果不喜欢用阻塞的方法来运行事件处理,Boost.Asio也提供了其它类似BSD socket的任务调度方法,poll就是其中之一。poll调用io_service的事件循环来运行已经就绪的handler方法,下面是一个poll的示例(用for模拟程序运行的循环):

[cpp] view plain copy print ?
  1. #include <boost/asio.hpp>   
  2. #include <iostream>   
  3.   
  4. int main( int argc, char * argv[] )  
  5. {  
  6.     boost::asio::io_service io_service;  
  7.   
  8.     forint x = 0; x < 42; ++x )  
  9.     {  
  10.         io_service.poll();  
  11.         std::cout << "Counter: " << x << std::endl;  
  12.     }  
  13.   
  14.     return 0;  
  15. }  

程序输出为0到41然后退出;如果这时也给io_service工作---work,而不reset,结果会是怎样呢?

[cpp] view plain copy print ?
  1. #include <boost/asio.hpp>   
  2. #include <iostream>   
  3.   
  4. int main( int argc, char * argv[] )  
  5. {  
  6.     boost::asio::io_service io_service;  
  7.     boost::asio::io_service::work work( io_service );  
  8.   
  9.     forint x = 0; x < 42; ++x )  
  10.     {  
  11.         io_service.poll();  
  12.         std::cout << "Counter: " << x << std::endl;  
  13.     }  
  14.   
  15.     return 0;  
  16. }  

        程序仍然输出为0到41然后退出。这是因为poll方法是非阻塞的,它只是检查当前工作队列中是否有就绪的,有就执行,然后立刻返回。在实际项目中,for循环一般是某种形式的事件循环。上面这个例子也说明了Boost.Asio的事件处理机制,work 对象给io_service对象提供工作内容,但如果在事件处理handler中再给io_service提供work,那么work将会递归无穷的产生,poll将永远不会结束。所以work的添加是在事件处理函数外部进行的。

     也就是说可以根据程序的设置,选择采用run()方法还是poll方法来运行程序。当然也有一些变体,run_one(),poll_one(),它们分别表示每次只执行一个事件处理handler,这在并发时能够很好的控制程序。

      从io_service.run()从io_service中删除work会使io_service.run()结束阻塞状态,但是io_service并没有这样的成员函数,这时必须通过智能指针来实现:通过reset智能指针来删除智能指针所指向的对象,这样就可以很优雅的移除work了。

[cpp] view plain copy print ?
  1. #include <boost/asio.hpp>   
  2. #include <boost/shared_ptr.hpp>   
  3. #include <iostream>   
  4.   
  5. int main( int argc, char * argv[] )  
  6. {  
  7.     boost::asio::io_service io_service;  
  8.     boost::shared_ptr< boost::asio::io_service::work > work(  
  9.         new boost::asio::io_service::work( io_service )  
  10.     );  
  11.   
  12.     work.reset();  
  13.   
  14.     io_service.run();  
  15.   
  16.     std::cout << "Do you reckon this line displays?" << std::endl;  
  17.   
  18.     return 0;     
  19. }  
       io_service支持多线程,在上一篇博文中也提到过,并且说明了io_service的线程调度顺序。下面是一个多线程的例子:

[cpp] view plain copy print ?
  1. void WorkerThread()  
  2. {  
  3.     std::cout << "Thread Start\n";  
  4.     io_service.run();  
  5.     std::cout << "Thread Finish\n";  
  6. }  
  7.   
  8. int main( int argc, char * argv[] )  
  9. {  
  10.     boost::shared_ptr< boost::asio::io_service::work > work(  
  11.         new boost::asio::io_service::work( io_service )  
  12.     );  
  13.   
  14.     std::cout << "Press [return] to exit." << std::endl;  
  15.   
  16.     boost::thread_group worker_threads;  
  17.     forint x = 0; x < 4; ++x )  
  18.     {  
  19.         worker_threads.create_thread( WorkerThread );  
  20.     }  
  21.   
  22.     std::cin.get();  
  23.   
  24.     io_service.stop();  
  25.   
  26.     worker_threads.join_all();  
  27.   
  28.     return 0;  
  29. }  
上面用到了stop。如果我们想让io_service把当前工作队列中的所有工作执行完毕后再结束,需要用上面提到的reset智能指针的方法而不是stop,而如果采用reset方法的时候不断的往io_service的工作队列中增加新的任务,那么它将永远也不会停下来。

你可能感兴趣的:(Boost-asio之二)