boost asio中io_service類的幾種使用

io_service類多線程

你應該已經發現大部分使用Boost.Asio編寫的代碼都會使用幾個io_service的實例。io_service是這個庫裏面
最重要的類;它負責和操做系統打交道,等待全部異步操做的結束,而後爲每個異步操做調用其完成處
理程序。
若是你選擇用同步的方式來建立你的應用,你則不須要考慮我將在這一節向你展現的東西。 你有多種不一樣
的方式來使用io_service。在下面的例子中,咱們有3個異步操做,2個socket鏈接操做和一個計時器等待操
做:
有一個io_service實例和一個處理線程的單線程例子:
io_service service; // 全部socket操做都由service來處理
ip::tcp::socket sock1(service); // all the socket operations are handled by service
ip::tcp::socket sock2(service); 異步

sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
service.run();
有一個io_service實例和多個處理線程的多線程例子:
io_service service;
ip::tcp::socket sock1(service);
ip::tcp::socket sock2(service);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
boost::thread( run_service);
void run_service()
{
service.run();
}
有多個io_service實例和多個處理線程的多線程例子:
io_service service[2];
ip::tcp::socket sock1(service[0]);
ip::tcp::socket sock2(service[1]);
sock1.asyncconnect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service[0], boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 2; ++i)
boost::thread( boost::bind(run_service, i));socket

void run_service(int idx)
{
service[idx].run();
}
首先,要注意你不能擁有多個io_service實例卻只有一個線程。下面的代碼片斷沒有任何意義:
for ( int i = 0; i < 2; ++i)
service[i].run();
上面的代碼片斷沒有意義是由於service[1].run()須要service[0].run()先結束。所以,全部由service[1]處理的
異步操做都須要等待,這顯然不是一個好主意。
在前面的3個方案中,咱們在等待3個異步操做結束。爲了解釋它們之間的不一樣點,咱們假設:過一會操做1
完成,而後接着操做2完成。同時咱們假設每個完成處理程序須要1秒鐘來完成執行。
在第一個例子中,咱們在一個線程中等待三個操做所有完成,第1個操做一完成,咱們就調用它的完成處理
程序。儘管操做2緊接着完成了,可是操做2的完成處理程序須要在1秒鐘後,也就是操做1的完成處理程序
完成時纔會被調用。
第二個例子,咱們在兩個線程中等待3個異步操做結束。當操做1完成時,咱們在第1個線程中調用它的完成
處理程序。當操做2完成時,緊接着,咱們就在第2個線程中調用它的完成處理程序(當線程1在忙着響應操
做1的處理程序時,線程2空閒着而且能夠迴應任何新進來的操做)。
在第三個例子中,由於操做1是sock1的connect,操做2是sock2的connect,因此應用程序會表現得像第二
個例子同樣。線程1會處理sock1 connect操做的完成處理程序,線程2會處理sock2的connect操做的完成處
理程序。然而,若是sock1的connect操做是操做1,deadline_timer t的超時操做是操做2,線程1會結束正
在處理的sock1 connect操做的完成處理程序。於是,deadline_timer t的超時操做必須等sock1 connect操
做的完成處理程序結束(等待1秒鐘),由於線程1要處理sock1的鏈接處理程序和t的超時處理程序。async

下面是你須要從前面的例子中學到的:
第一種狀況是很是基礎的應用程序。由於是串行的方式,因此當幾個處理程序須要被同時調用時,你
一般會遇到瓶頸。若是一個處理程序須要花費很長的時間來執行,全部隨後的處理程序都不得不等
待。
第二種狀況是比較適用的應用程序。他是很是強壯的——若是幾個處理程序被同時調用了(這是有可
能的),它們會在各自的線程裏面被調用。惟一的瓶頸就是全部的處理線程都很忙的同時又有新的處
理程序被調用。然而,這是有快速的解決方式的,增長處理線程的數目便可。
第三種狀況是最複雜和最難理解的。你只有在第二種狀況不能知足需求時才使用它。這種狀況通常就
是當你有成千上萬實時(socket)鏈接時。你能夠認爲每個處理線程(運行io_service::run()的線
程)有它本身的select/epoll循環;它等待任意一個socket鏈接,而後等待一個讀寫操做,當它發現這
種操做時,就執行。大部分狀況下,你不須要擔憂什麼,惟一你須要擔憂的就是當你監控的socket數
目以指數級的方式增加時(超過1000個的socket)。在那種狀況下,有多個select/epoll循環會增長應
用的響應時間。
若是你以爲你的應用程序可能須要轉換到第三種模式,請確保監聽操做的這段代碼(調用io_service::run()
的代碼)和應用程序其餘部分是隔離的,這樣你就能夠很輕鬆地對其進行更改。tcp

相關文章
相關標籤/搜索