ASIO的實現,其實就是基於Proactor pattern,在這裡我們先不對這個pattern做探討,等以後有機會再來談
想像io_service即是os跟我們程式之間的橋梁,
當執行io_service.run()的時候,便是將系統轉移到os上,
並block住原本的程式,直至所有的工作佇列完成,其是一種synchronous 模式。
只是,有時候我們並不希望程式在完成工作之後就結束,而是繼續等待是否有其他工作傳入,這時候我們就可以加入
boost::asio::io_service::work work( io_service );,以便讓系統能夠持續的運行。
完整程式碼如下:
#include <boost/asio.hpp> #include <iostream> int main( int argc, char * argv[] ){ boost::asio::io_service io_service; boost::asio::io_service::work work( io_service ); io_service.run(); std::cout < < "這行永遠到不了" << std::endl; return 0; }
為什麼會這樣呢?那是因為work object 提供一個work給 io_service object這件事,本身就是一個會被加入到Completion Event Queue裡面的工作。(Completion Event Queue是一組由linked list組成的function object,在boost裡面通常是用Bind函數實現。)
雖然這種做法可以確保所有非同步的工作都被完成,但是,其缺點就是會讓我們的程式陷入無窮的等待中而無法進行別的事情。那麼是不是有一個方法,可以讓我們在執行這些非同步的工作之餘也去處理其他的程序呢?當然,作為一個完整用來處理非同步問題的函式庫,asio當然會提供這樣的一個方法。
在io_service的成員函數中,我們可以發現有以下幾個方法:
poll():處理所有已被加入到工作佇列中的ready handler
poll_one(): 只處理『一個』已被加入工作佇列中的ready handler
所謂的ready handler,指的就是已完成非同步的操作及等待(例如:data已藉由網路傳輸完成),被加入Completion Event Queue的handler
這些function用來定義當非同步操作等待完成後所該進行的工作
在windowsNT、XP及2000之後的系列上 Completion Event Queue等同於I/O completion port。而每個io_service instance都會擁有一個I/O completion port。
依程式需求選擇poll()、poll_one(),我們可以改寫上一篇的程式碼,來達成asynchronous的模式:
#include <boost/asio.hpp> #include <iostream> using namespace std; void handler1(const boost::system::error_code &ec) { std::cout < < "5 s." << std::endl; system("pause"); } void handler2(const boost::system::error_code &ec) { std::cout << "10 s." << std::endl; system("pause"); } int main() { boost::asio::io_service io_service; boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5)); timer1.async_wait(handler1); boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(10)); timer2.async_wait(handler2); int i = 0; while(true){ io_service.poll(); cout << "counter:" << i << endl; i++; } system("pause"); }
使用run()、run_one()、poll()以及poll_one()的分別:
run():等待並將工作佇列中的任務全部處理完再繼續執行 (Blocking 模式)
poll():去看Completion Event Queue中是否有待處理的handler,有的話就全部執行,沒有的話就繼續執行我們的主程序(non-Blocking 模式)
run_one():等待並確實的執行『一個』Completion Event Queue中的handler
poll_one():只執行一個Completion Event Queue中的handler
在ASIO中是以先進先出法來取得Completion Event Queue裡面的handler
Leave a Reply