1. 程式人生 > >Boost asio學習筆記之一—— 使用strand支援多執行緒呼叫service_io的方法

Boost asio學習筆記之一—— 使用strand支援多執行緒呼叫service_io的方法

asio是一個跨平臺的網路庫,可以作為boost的一部分,也可以使用獨立的asio部分。這裡記錄學習的筆記,作為參考。

感覺asio的關鍵就是io_service物件。所有的非同步同步都跟這個有關。多執行緒方式下要asio::strand來解決。下面用timmer.5為例在進行研究。

(1)首先建立專案。

因為是新手,對於linux下的開發環境不熟悉,經過對比,我選擇了用netbeans作為c++的ide工具。先在netbeans裡面建立一個空專案,然後,增加一個timmer.cpp的檔案,拷進如下內容(內容來自asio 1.4.1的tutorial,timmer 5):

//
// timer.cpp
// ~~~~~~~~~ // // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include <iostream> #include <asio.hpp> #include <boost
/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class printer { public: printer(asio::io_service& io) : strand_(io), timer1_(io, boost::posix_time::seconds(1)), timer2_(io, boost::posix_time::seconds(1)), count_(0) { timer1_.async_wait(strand_.wrap
(boost::bind(&printer::print1, this))); timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this))); } ~printer() { std::cout << "Final count is " << count_ << "/n"; } void print1() { if (count_ < 10) { std::cout << "Timer 1: " << count_ << "/n"; ++count_; timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1)); timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this))); } } void print2() { if (count_ < 10) { std::cout << "Timer 2: " << count_ << "/n"; ++count_; timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1)); timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this))); } } private: asio::strand strand_; asio::deadline_timer timer1_; asio::deadline_timer timer2_; int count_; }; int main() { asio::io_service io; printer p(io); asio::thread t(boost::bind(&asio::io_service::run, &io)); io.run(); t.join(); return 0; }

然後在include path裡面加上asio的include目錄。
接下來編譯發現報錯,原來我用的是單獨的asio包,在linux下需要連線pthread來實現多執行緒。所以,又在c++編譯器的命令列引數裡面加了一個引數:-pthread。這個問題困擾了我一天,最後查閱了asio自己的makefile檔案才發現了這個引數,加上後就好了。

這個定時器的例子比較複雜,看了一下以後沒太搞清楚,於是在網上又找了一個別的例子進行參考,連線如下:

http://cunsh.ycool.com/post.2150877.html

比如其中的例子2:

例子2: 使用一個非同步的定時器

//一個將被定時器非同步呼叫的函式.
void print(const boost::system::error_code& /*e*/)
{
std::cout << “Hello, world!/n”;
}

int main()
{
boost::asio::io_service io;

boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
//和例子1不同. 這裡呼叫 async_wait() 執行一個非同步的等待. 它註冊一個可執行體(即此處的print函式).   //這裡不懂的是: print的引數怎麼傳入?
//實際上. 這個執行體被註冊到 deadline_timer 類的 io_service 成員上(即本例的 io 物件). 只有在以後呼叫 io.run() 時這些註冊的執行體才會被真正執行.
t.async_wait(print);

//呼叫 io物件的 run() 函式執行那些被註冊的執行體.
//這個函式不會立即返回. 除非和他相關的定時器物件超時並且在定時器超時後執行完所有註冊的執行體. 之後才返回.
//所以它在這裡阻塞一會兒. 等t超時後執行完print. 才返回.
//這裡要注意的是. 呼叫 io.run() 可以放在其它執行緒中. 那樣所有的回撥函式都在別的執行緒上執行.
io.run();

return 0;
}

看過這個例子後,知道了boost timer的大致工作原理,開始那個例子的工作過程也有個大概的瞭解。現註冊service_io物件,然後通過printer的建構函式註冊兩個deadline timer,一秒鐘後超時。

printer(asio::io_service& io)
: strand_(io),
timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)

接著,通過timer的async_wait函式註冊超時處理函式print1和print2。

timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));

可以用 deadline_timer::expires_at()來獲取/設定 超時的時間點,在這裡我們將超時的時間點向後推遲一秒:

t->expires_at(t->expires_at() + boost::posix_time::seconds(1));

對於:

timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));

boost::asio::strand 類可以把幾個print包裝成同步執行的. 這樣就保證了在任何時刻. print1和 print2 都不會同時在執行.