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