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 都不会同时在执行.