boost------asio庫的使用1(Boost程序庫徹底開發指南)讀書筆記

asio庫基於操做系統提供的異步機制,採用前攝器設計模式(Proactor)實現了可移植的異步(或者同步)IO操做,並且並不要求多線程和鎖定,有效地避免了多線程編程帶來的諸多有害反作用。ios

 

目前asio主要關注於網絡通訊方面,使用大量的類和函數封裝了socket API,支持TCP、TCMP、UDP等網絡通訊協議。但asio的異步操做並不侷限於網絡編程,它還支持串口讀寫、定時器、SSL等功能,並且asio是一個很好的富有彈性的框架,能夠擴展到其餘有異步操做須要的領域編程

 

 

概述設計模式

asio庫基於前攝器模式封裝了操做系統的select、poll/epoll、kqueue、overlapped I/O等機制,實現了異步IO模型。它的核心類io_service,至關於前攝器模式中的Proactor角色,asio的任何操做都須要有io_service的參與。網絡

 

在同步模式下,程序發起一個IO操做,向io_service提交請求,io_service把操做轉交給操做系統,同步地等待。當IO操做完成時,操做系統通知io_service,而後io_service再把結果發回給程序,完成整個同步流程。這個處理流程與多線程的join()等待方式很類似。多線程

 

在異步模式下,程序除了要發起的IO操做,還要定義一個用於回調的完成處理函數。io_service一樣把IO操做轉交給操做系統執行,但它不一樣步等待,而是當即返回。調用io_service的run()成員函數能夠等待異步操做完成,當異步操做完成時io_service從操做系統獲取執行結果,調用完成處理函數。app

 

asio不直接使用操做系統提供的線程,而是定義了一個本身的線程概念:strand,它保證在多線程的環境中代碼能夠正確地執行,而無需使用互斥量。io_service::strand::wrap()函數能夠包裝一個函數在strand中執行。框架

 

asio庫使用system庫的error_code和system_error來表示程序運行的錯誤。異步

 

定時器

 

定時器是asio庫裏最簡單的一個IO模型示範,提供等待時間終止的功能,經過它咱們能夠快速熟悉asio的基本使用方法:socket

同步定時器

 

[cpp] view plain copyasync

 print?在CODE上查看代碼片派生到個人代碼片

  1. #include "stdafx.h"  
  2. #include "boost/asio.hpp"  
  3. #include "boost/date_time/posix_time/posix_time.hpp"  
  4. #include "iostream"  
  5. using namespace std;  
  6.   
  7.   
  8. int _tmain(int argc, _TCHAR* argv[])  
  9. {  
  10.     boost::asio::io_service ios;    // 因此的asio程序必需要有一個io_service對象  
  11.   
  12.     // 定時器io_service做爲構造函數參數,兩秒鐘以後定時器終止  
  13.     boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));  
  14.   
  15.     cout << t.expires_at() << endl; // 查看終止的絕對事件  
  16.   
  17.     t.wait();                       // 調用wait同步等待  
  18.     cout << "hello asio" << endl;  
  19.   
  20.     return 0;  
  21. }  

 

 

能夠把它與thread庫的sleep()函數對比研究一下,二者都是等待,但內部機制完成不一樣:thread庫的sleep()使用了互斥量和條件變量,在線程中等待,而asio則是調用了操做系統的異步機制,如select、epoll等完成的。

 

 

異步定時器

下面的是異步定時器,代碼大體與同步定時器相等,增長了回調函數,並使用io_service.run()和定時器的async_wait()方法

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. #include "stdafx.h"  
  2. #include "boost/asio.hpp"  
  3. #include "boost/date_time/posix_time/posix_time.hpp"  
  4. #include "iostream"  
  5. using namespace std;  
  6.   
  7.   
  8. void Print(const boost::system::error_code& error)  
  9. {  
  10.     cout << "hello asio" << endl;  
  11. }  
  12.   
  13.   
  14. int _tmain(int argc, _TCHAR* argv[])  
  15. {  
  16.     boost::asio::io_service ios;    // 因此的asio程序必需要有一個io_service對象  
  17.   
  18.     // 定時器io_service做爲構造函數參數,兩秒鐘以後定時器終止  
  19.     boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));  
  20.   
  21.     t.async_wait(Print);                        // 調用wait異步等待  
  22.   
  23.     cout << "it show before t expired." << endl;  
  24.   
  25.     ios.run();  
  26.   
  27.     return 0;  
  28. }  

代碼的前兩行與同步定時器相同,這是全部asio程序基本的部分。重要的是異步等待async_wait(),它通知io_service異步地執行io操做,而且註冊了回調函數,用於在io操做完成時由事件多路分離器分派返回值(error_code)調用

 

最後必須調用io_service的run()成員函數,它啓動前攝器的事件處理循環,阻塞等待全部的操做完成並分派事件。若是不調用run()那麼雖然操做被異步執行了,但沒有一個等待它完成的機制,回調函數將得不到執行機會。

 

 

異步定時器使用bind

異步定時器中因爲引入了回調函數,所以產生了不少的變化,能夠增長回調函數的參數,使它可以作更多的事情。但async_wait()接受的回調函數類型是固定的,必須使用bind庫來綁定參數以適配它的接口

   下面實現一個能夠定時執行任意函數的定時器AsynTimer(asyctimer),它持有一個asio定時器對象和一個計數器,還有一個function對象來保存回調函數

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. #include "stdafx.h"  
  2. #include "boost/asio.hpp"  
  3. #include "boost/date_time/posix_time/posix_time.hpp"  
  4. #include "boost/bind.hpp"  
  5. #include "boost/function.hpp"  
  6. #include "iostream"  
  7. using namespace std;  
  8.   
  9.   
  10. class AsynTimer  
  11. {  
  12. public:  
  13.     template<typename F>                              // 模板類型,能夠接受任意可調用物  
  14.     AsynTimer(boost::asio::io_service& ios, int x, F func)  
  15.         :f(func), count_max(x), count(0),               // 初始化回調函數和計數器  
  16.         t(ios, boost::posix_time::millisec(500))        // 啓動計時器  
  17.     {  
  18.         t.async_wait(boost::bind(&AsynTimer::CallBack,  // 異步等待計時器  
  19.             this, boost::asio::placeholders::error));   // 註冊回調函數  
  20.     }  
  21.   
  22.     void CallBack(const boost::system::error_code& error)  
  23.     {  
  24.         if (count >= count_max)   // 若是計數器達到上限則返回  
  25.         {  
  26.             return;  
  27.         }  
  28.         ++count;  
  29.         f();                     // 調用function對象  
  30.   
  31.         // 設置定時器的終止時間爲0.5秒以後  
  32.         t.expires_at(t.expires_at() + boost::posix_time::microsec(500));  
  33.         // 再次啓動定時器,異步等待  
  34.         t.async_wait(boost::bind(&AsynTimer::CallBack, this, boost::asio::placeholders::error));  
  35.     }  
  36.   
  37. private:  
  38.     int count;  
  39.     int count_max;  
  40.     boost::function<void()> f;        // function對象,持有無參無返回值的可調用物  
  41.     boost::asio::deadline_timer t;  // asio定時器對象  
  42. };  
  43.   
  44. // 第一個回調函數  
  45. void print1()  
  46. {  
  47.     cout << "hello asio" << endl;  
  48. }  
  49.   
  50. // 第二個回調函數  
  51. void print2()  
  52. {  
  53.     cout << "hello boost" << endl;  
  54. }  
  55.   
  56.   
  57. int _tmain(int argc, _TCHAR* argv[])  
  58. {  
  59.     boost::asio::io_service ios;  
  60.   
  61.     AsynTimer t1(ios, 10, print1); // 啓動第一個定時器  
  62.     AsynTimer t2(ios, 10, print2); // 啓動第二個定時器  
  63.   
  64.     ios.run();  // io_service等待異步調用結束  
  65.   
  66.     return 0;  
  67. }  

 

注意在async_wait()中bind的用法,CallBack是AsynTimer的一個成員函數,所以須要綁定this指針,同時還使用了asio下子名字空間placeholders下的一個佔位符error,他的做業相似於bind庫的佔位符_一、_2,用於傳遞error_code值。

 

接下來是AsynTimer的主要功能函數CallBack,它符合async_wait()對回調函數的要求,有一個error_code參數,當定時器終止時它將被調用執行

 

CallBack函數內部累加器,若是計數器未達到上限則調用function對象f,而後從新設置定時器的終止時間,再次異步等待被調用,從而達到反覆執行的目的

相關文章
相關標籤/搜索