Boost.Asio翻译整理(二)

Boost.Asio定时器
本文介绍了Boost.Asio库中定时器的使用方法,包括同步和异步等待,并展示了如何通过回调函数实现定时任务,适用于多线程环境。

示例1:

Timer.1 - Using a timer synchronously

使用定时器演示一个阻塞等待

这个示例程序通过展示在定时器中执行一个阻塞等待( blocking wait )来介绍Asio。
让我们从必须包含的头文件开始。
  • 所有的Asio类只要简单的包含"asio.hpp"头文件便可使用。
  • 因为本程序中使用了定时器,我们需要包含相应的的Boost.Date_Time 头文件来处理时间操作。

#include <iostream> #include <boost/asio.hpp> #include<boost/date_time/posix_time/posix_time.hpp> int main() { boost::asio::io_service io; boost::asio::deadline_timer t(io,boost::posix_time::seconds(5)); t.wait(); // 最后我们打印出“Hello,world”信息以显示定时器已经终止。 std::cout << "Hello, world!"; return 0; } 说明:
说明1: 使用Asio的所有程序都至少需要一个提供访问I/O功能的boost::asio::io_service对象。
因此在主函数中我们做的第一件事就是声明一个这个类型的对象。

说明2: boost::asio::deadline_timer类是作为Asio的核心类。
它提供的I/O功能(在此为定时器功能),通常用一个io_service 的引用作为其构造函数的第一个参数。
第二个参数设置一个从现在开始5秒后终止的定时器。

说明3: deadline_timer::wait()函数调用直到定时器终止(从定时器被创建算起,五秒后终止)才会返回。
一个deadline timer 通常是下面两种状态中的一种:"expired(终止)" 或"not expired(不终止)"。
deadline_timer::wait()函数如果被一个已经终止的定时器调用, 它将立即返回。

查看本例的全部源码:full source listing

---------------------------------------------------- 分割线 ---------------------------------------------------

示例2:

Timer.2 - Using a timer asynchronously


这个示例程序示范了如何通过修改Timer.1 中的程序,使用Asio的异步回调功能在定时器中演示一个异步等待。

#include <iostream> #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> //异步等待结束将被调用的函数 void print(const boost::system::error_code& /*e*/) { std::cout << "Hello, world! "; } int main() { boost::asio::io_service io; boost::asio::deadline_timer t(io, boost::posix_time::seconds(5)); //执行一个异步等待,并传入上面定义的print回调句柄。 t.async_wait(print); io.run(); return 0; } 说明:
1, 使用Asio的异步功能意味着当一个异步操作完成时一个回调函数将被调用。在本程序中我们定义一个
名为“print”的函数,在异步等待结束后这个函数将被调用。
2, 必须在io_service对象上调用io_service::run() 成员函数。
Asio保证回调句柄仅仅能被boost::asio::io_service::run()启动的当前线程所调用。因此,
如果boost::asio::io_service::run() 函数不执行,用于异步等待完成时的回调函数(在本例中为print函数)将永远不
会被调用。 当仍旧有“工作”可做时,boost::asio::io_service::run() 函数会继续运行。在本例中,
“工作”是定时器的异步等待,因此,直到定时器终止和回调函数执行完成,程序才会返回。


在调用boost::asio::io_service::run()之前确保给io_service 一些工作去做,这非常重要。
例如,如果我们省略了上面调用的boost::asio::deadline_timer::async_wait()函数,
io_service对象将没有任何事情去做,因此boost::asio::io_service::run() 将立即返回


查看本例的全部源码:full source listing

---------------------------------------------------- 分割线 ---------------------------------------------------

示例3:

Timer.3 - Binding arguments to a handler

在本示例程序中我们将修改Timer.2中的例子,使定时器每秒被激活一次。例子将示范如何给你的函数指针传递附加参数。
查看本例的全部源码:full source listing

// 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 <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> void print(const boost::system::error_code& /*e*/, boost::asio::deadline_timer* t, int* count) { if (*count < 5) { std::cout << *count << " "; ++(*count); //推迟定时器的终止时间。在原先的终止时间上增加延时,确保定时器不会在处理回调函数所需时间内到期 t->expires_at(t->expires_at() + boost::posix_time::seconds(1)); t->async_wait(boost::bind(print, boost::asio::placeholders::error, t, count)); } } int main() { boost::asio::io_service io; int count = 0; boost::asio::deadline_timer t(io, boost::posix_time::seconds(1)); //在第四步中,当在主函数中的调用boost::asio::deadline_timer::async_wait() 函数时, //我们绑定print函数所需要的附加参数。 t.async_wait(boost::bind(print, boost::asio::placeholders::error, &t, &count)); io.run(); std::cout << "Final count is " << count << " "; return 0; }

说明:
1, 需要熟悉了解boost::bind库
2, 使用Asio实现一个重复定时器,你必须在你的回调函数中去改变定时器的终止时间,然后开始一个新的异步等待。
显然这意味着回调函数必须拥有改变定时器对象的权限。为此我们为print函数增加两个新参数。
一个指向定时器对象的指针
一个用于当定时器第6次被激活时我们可以中止程序的计数器
3,在定时器中启动一个新的异步等待。我们必须使用boost::bind() 函数给你的回调函数绑定额外的参数,
因为boost::asio::deadline_timer::async_wait() 函数只期望得到一个拥用
void(constboost::system::error_code&)签名的函数指针(或函数对象)。


在本例中,boost::bind()的boost::asio::placeholders::error参数是为了给回调函数传入一个error对象。
当开始异步操作时,如果使用boost::bind(),你必须指定和回调函数的参数列表相匹配的一个参数。

---------------------------------------------------- 分割线 ----------------------------------------------------------------------

示例4:

在本例中我们将看到怎样使用类成员函数作为回调句柄。程序完成和Timer.3完全同样的功能。

查看本例的全部源码:full source listing

// 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 <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class printer { public: printer(boost::asio::io_service& io) : timer_(io, boost::posix_time::seconds(1)), count_(0) { timer_.async_wait(boost::bind(&printer::print, this)); } ~printer() { std::cout << "Final count is " << count_ << " "; } void print() { if (count_ < 5) { std::cout << count_ << " "; ++count_; timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1)); timer_.async_wait(boost::bind(&printer::print, this)); } } private: boost::asio::deadline_timer timer_; int count_; }; int main() { boost::asio::io_service io; printer p(io); io.run(); return 0; }

---------------------------------------------------- 分割线 ----------------------------------------------------------------------

示例5:

本示例程序示范了使用boost::asio::strand 类来创建多线程程序中的同步回调句柄。

前四个例程只是在线程下使用boost::asio::io_service::run()函数来避免处理函同步。如你所见,Asio库保证回调句柄仅能被当前正在调用boost::asio::io_service::run()函数的线程调用。因此,在线程中调用boost::asio::io_service::run()能确保回调句柄不被并发运行


单线程通常是使用Asio开发应用程序最好的方式。下面是Asio在程序中的局限性,尤其是服务器方面,包括:

  • 操作需要较长时间处理才能完成时弱响应
  • 在大规模的多处理机系统中表现不佳
如果你发现自己陷入这些局限时,一个可供选择的方法是创建一个每个线程都调用boost::asio::io_service::run()的线程池。不过,因为这允许并发操作,当访问一个共享、非线程安全的资源时,我们需要一个同步方式。#include <iostream> #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class printer { public: printer(boost::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_ << " "; } void print1() { if (count_ < 10) { std::cout << "Timer 1: " << count_ << " "; ++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_ << " "; ++count_; timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1)); timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this))); } } private: boost::asio::strand strand_; boost::asio::deadline_timer timer1_; boost::asio::deadline_timer timer2_; int count_; }; int main() { boost::asio::io_service io; printer p(io); boost::thread t(boost::bind(&boost::asio::io_service::run, &io)); io.run(); t.join(); return 0; }
说明:
1,在主函数中,boost::asio::io_service::run() 现在被两个线程调用:主线程和一个附加线程。这一切依赖于boost::thread对象来完成。正如它被一个单线程调用一样,boost::asio::io_service::run() 的并发调用会一直持续到无任何“工作”可做。后台线程直到所有异步操作都完成后才会退出。

2, 在一个多线程程序中,当访问同一共享资源时,异步操作必须是同步的。在本例中,print1和print2函数使用的共享资源为std::cout 和count_数据成员。

3, 除了初始化一对boost::asio::deadline_timer 成员变量外,构造函数还初始化一个boost::asio::strand类型的strand_成员变量。
boost::asio::strand 对象保证:对于通过它来分派执行的众操作中,只有一个操作执行完成之后才允许进入下一个操作。
这种保证与多少个线程调用boost::asio::io_service::run()无关。
当然,如果不是通过一个boost::asio::strand对象分派,或者通过其它不同的boost::asio::strand对象分派,这些操作仍旧可能是并发的
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
上一篇: Boost.Asio翻译(一) 下一篇: Boost.Asio翻译(三)--DayTime1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值