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?
- #include "stdafx.h"
- #include "boost/asio.hpp"
- #include "boost/date_time/posix_time/posix_time.hpp"
- #include "iostream"
- using namespace std;
-
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- boost::asio::io_service ios; // 因此的asio程序必需要有一個io_service對象
-
- // 定時器io_service做爲構造函數參數,兩秒鐘以後定時器終止
- boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));
-
- cout << t.expires_at() << endl; // 查看終止的絕對事件
-
- t.wait(); // 調用wait同步等待
- cout << "hello asio" << endl;
-
- return 0;
- }
能夠把它與thread庫的sleep()函數對比研究一下,二者都是等待,但內部機制完成不一樣:thread庫的sleep()使用了互斥量和條件變量,在線程中等待,而asio則是調用了操做系統的異步機制,如select、epoll等完成的。
異步定時器
下面的是異步定時器,代碼大體與同步定時器相等,增長了回調函數,並使用io_service.run()和定時器的async_wait()方法
[cpp] view plain copy
print?
- #include "stdafx.h"
- #include "boost/asio.hpp"
- #include "boost/date_time/posix_time/posix_time.hpp"
- #include "iostream"
- using namespace std;
-
-
- void Print(const boost::system::error_code& error)
- {
- cout << "hello asio" << endl;
- }
-
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- boost::asio::io_service ios; // 因此的asio程序必需要有一個io_service對象
-
- // 定時器io_service做爲構造函數參數,兩秒鐘以後定時器終止
- boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));
-
- t.async_wait(Print); // 調用wait異步等待
-
- cout << "it show before t expired." << endl;
-
- ios.run();
-
- return 0;
- }
代碼的前兩行與同步定時器相同,這是全部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?
- #include "stdafx.h"
- #include "boost/asio.hpp"
- #include "boost/date_time/posix_time/posix_time.hpp"
- #include "boost/bind.hpp"
- #include "boost/function.hpp"
- #include "iostream"
- using namespace std;
-
-
- class AsynTimer
- {
- public:
- template<typename F> // 模板類型,能夠接受任意可調用物
- AsynTimer(boost::asio::io_service& ios, int x, F func)
- :f(func), count_max(x), count(0), // 初始化回調函數和計數器
- t(ios, boost::posix_time::millisec(500)) // 啓動計時器
- {
- t.async_wait(boost::bind(&AsynTimer::CallBack, // 異步等待計時器
- this, boost::asio::placeholders::error)); // 註冊回調函數
- }
-
- void CallBack(const boost::system::error_code& error)
- {
- if (count >= count_max) // 若是計數器達到上限則返回
- {
- return;
- }
- ++count;
- f(); // 調用function對象
-
- // 設置定時器的終止時間爲0.5秒以後
- t.expires_at(t.expires_at() + boost::posix_time::microsec(500));
- // 再次啓動定時器,異步等待
- t.async_wait(boost::bind(&AsynTimer::CallBack, this, boost::asio::placeholders::error));
- }
-
- private:
- int count;
- int count_max;
- boost::function<void()> f; // function對象,持有無參無返回值的可調用物
- boost::asio::deadline_timer t; // asio定時器對象
- };
-
- // 第一個回調函數
- void print1()
- {
- cout << "hello asio" << endl;
- }
-
- // 第二個回調函數
- void print2()
- {
- cout << "hello boost" << endl;
- }
-
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- boost::asio::io_service ios;
-
- AsynTimer t1(ios, 10, print1); // 啓動第一個定時器
- AsynTimer t2(ios, 10, print2); // 啓動第二個定時器
-
- ios.run(); // io_service等待異步調用結束
-
- return 0;
- }
注意在async_wait()中bind的用法,CallBack是AsynTimer的一個成員函數,所以須要綁定this指針,同時還使用了asio下子名字空間placeholders下的一個佔位符error,他的做業相似於bind庫的佔位符_一、_2,用於傳遞error_code值。
接下來是AsynTimer的主要功能函數CallBack,它符合async_wait()對回調函數的要求,有一個error_code參數,當定時器終止時它將被調用執行
CallBack函數內部累加器,若是計數器未達到上限則調用function對象f,而後從新設置定時器的終止時間,再次異步等待被調用,從而達到反覆執行的目的