1:steady_timer的expires_from_now函数参数必须使用std::chrono

2:deadline_timer的expires_from_now函数参数必须使用boost::posix_time

声明以下处之别人的整理中

3:boost::asio::deadline_timer使用的计量时间是系统时间,因此修改系统时间会影响deadline_timer的行为。例如,调用了expires_from_now设置1分钟超时后,立刻把系统时间改成一天前,那么要过一天时间才会超时。这个特性可能会影响程序功能的正常使用,因此我们通常想要的是一个不会受系统时间影响的定时器。

事实上,boost::asio::steady_timer就是一个这样的定时器,它基于std::chrono::steady_clock实现。std::chrono::steady_clock是一个稳定的时钟,不随系统时间变化而变化。既然如此,直接用steady_timer代替deadline_timer不就可以了吗?理论上来说是可以的,但实际上,在Visual C++ 2013环境下,这是行不通的,因为Visual C++ 2013标准库中的std::chronno::steady_clock并不符合标准,它仍然会受系统时间影响!

有三种方法可以解决这个问题。第一是升级到Visual C++ 2015,这个版本的std::chronno::steady_clock总算符合标准了;第二是修改boost的编译选项,定义BOOST_ASIO_DISABLE_STD_CHRONO宏,这样可以禁止boost使用std::chrono,转而使用boost::chrono;第三是本文要介绍的方法,即定制deadline_timer,让它变成稳定的定时器。

deadline_timer实际上是basic_deadline_timer的特化版本,它的定义如下:

typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
basic_deadline_timer是一个模板类,它的定义如下:

template<
    typename Time,
    typename TimeTraits = boost::asio::time_traits<Time>,
    typename TimerService = deadline_timer_service<Time, TimeTraits>>
class basic_deadline_timer : public basic_io_object< TimerService >
从以上定义的模板参数可以看出,basic_deadline_timer提供了灵活的可定制性。这里我们关注的重点是前面两个模板参数,其中第一个参数Time指定时间值的类型,第二个参数TimeTraits指定时间值的特性类,特性类用来对时间值进行各种操作。TimeTraits使用boost::asio::time_traits作为默认值,而boost::asio::time_traits只有一个针对boost::posix_time::ptime(即deadline_timer使用的时间值类型)的特化版本,从这个特化版本的定义可以看到TimeTraits需要提供哪些接口,如下所示:

/// Time traits specialised for posix_time.
template <>
struct time_traits<boost::posix_time::ptime>
{
  /// The time type.
  typedef boost::posix_time::ptime time_type;

/// The duration type.
  typedef boost::posix_time::time_duration duration_type;

/// Get the current time.
  static time_type now()
  {
#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
    return boost::posix_time::microsec_clock::universal_time();
#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
    return boost::posix_time::second_clock::universal_time();
#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
  }

/// Add a duration to a time.
  static time_type add(const time_type& t, const duration_type& d)
  {
    return t + d;
  }

/// Subtract one time from another.
  static duration_type subtract(const time_type& t1, const time_type& t2)
  {
    return t1 - t2;
  }

/// Test whether one time is less than another.
  static bool less_than(const time_type& t1, const time_type& t2)
  {
    return t1 < t2;
  }

/// Convert to POSIX duration type.
  static boost::posix_time::time_duration to_posix_duration(
      const duration_type& d)
  {
    return d;
  }
};
可以看到,TimeTraits需要提供time_type和duration_type两种类型来分别表示一个时间点和一段时间;需要提供now方法来获取当前时间;需要提供add、subtract和less_than方法来计算和比较时间;最后还需要to_posix_duration方法把duration_type类型转换成boost::posix_time::time_duration类型。

显然,对于定制的basic_deadline_timer,时间值类型Time可以是任意类型,并且它的含义并没有硬性规定,例如,它可以是以毫秒或纳秒为单位的时间,也可以是CPU时钟的周期数,只要提供了正确的TimeTraits特性类把这个定制的时间值转换成boost认识的时间值即可。

接下来要选择一种与系统时间无关的时间值类型来定制basic_deadline_timer。在Windows平台下,很容易想到可以使用QueryPerformanceCounter和QueryPerformanceFrequency,这两个API提供了高精度的时间度量,与系统时间无关。QueryPerformanceCounter用来查询当前CPU时钟的周期数,是64位整数,这个是理想的时间值类型。要把CPU时钟周期数转换成具体的时间还需要调用QueryPerformanceFrequency查询CPU时钟的频率,即1秒内的CPU时钟周期数,然后通过简单的计算即可得到。

下面的是使用QueryPerformanceCounter和QueryPerformanceFrequency定制的TimeTraits:

class TimeTraits {
public:
    typedef std::int64_t time_type;

class duration_type {
    public:
        duration_type() : value(0) { }
        duration_type(std::int64_t value) : value(value) { }

std::int64_t value;
    };

public:
    static void Initialize() {

LARGE_INTEGER frequence_large_integer = { 0 };
        QueryPerformanceFrequency(&frequence_large_integer);
        frequence = frequence_large_integer.QuadPart;
    }

static duration_type GetMinutes(std::int64_t minutes) {
        return duration_type(minutes * 60 * frequence);
    }

static duration_type GetSeconds(std::int64_t seconds) {
        return duration_type(seconds * frequence);
    }

static duration_type GetMilliseconds(std::int64_t milliseconds) {
        return duration_type(milliseconds * (frequence / 1000));
    }

static time_type now() {

LARGE_INTEGER counter = { 0 };
        QueryPerformanceCounter(&counter);
        return counter.QuadPart;
    }

static time_type add(time_type time, duration_type duration) {
        return time + duration.value;
    }

static duration_type subtract(time_type time1, time_type time2) {
        return duration_type(time1 - time2);
    }

static bool less_than(time_type time1, time_type time2) {
        return time1 < time2;
    }

static boost::posix_time::time_duration to_posix_duration(duration_type duration) {

std::int64_t microseconds = (duration.value * 1000 * 1000) / frequence;
        return boost::posix_time::microseconds(microseconds);
    }

private:
    TimeTraits();

private:
    static std::int64_t frequence;
};
CPU时钟的频率是固定的,只需要调用QueryPerformanceFrequency查询一次即可,因此这里增加了Initialize方法来初始化CPU时钟频率,要在程序启动后的某个时机来调用该方法进行初始化。要注意的是duration_type不能跟time_type相同,这是TimeTraits的硬性规定,boost内部的代码依赖了这个规定,违反它会导致编译失败。所以要针对duration_type额外定义一个看似冗余的类型。

另一个值得注意的地方是,上面的定义增加了GetMinutes、GetSeconds和GetMilliseconds方法,这几个方法用来将具体的时间转换成我们定制的时间值,即CPU时钟周期数。这是因为在调用定时器的expires_from_now等方法设置超时值的时候,必须使用TimeTraits的duration_type,提供这几个方法可以方便使用。

最后,将这个定制的TimeTraits作为basic_deadline_timer的模板参数即可:

typedef boost::asio::basic_deadline_timer<std::int64_t, TimeTraits> Timer
使用方法基本上与dealine_timer一样,如下所示:

//在某个时机初始化TimeTraits
TimeTraits::Initialize();

//在某个地方定义io_service
boost::asio::io_service io_service;

//使用定制的Timer
Timer timer(io_service);
timer.expires_from_now(TimeTraits::GetSecnods(10));
timer.wait();

 
 
 

boost库下的deadline_timer和steady_timer 区别相关推荐

  1. Boost库之asio io_service以及run、run_one、poll、poll_one区别

    Boost库之asio io_service以及run.run_one.poll.poll_one区别 原文:http://blog.csdn.net/byxdaz/article/details/7 ...

  2. Windows下Boost库的安装与使用

    目录 1.基本介绍 2.下载安装 3.配置boost环境(VS2010) 4.测试 1.基本介绍 Boost库是为C++语言标准库提供扩展的一些C++程序库的总称,由Boost社区组织开发.维护.其目 ...

  3. Mysql依赖库Boost的源码安装,linux下boost库的安装

    boost'准标准库'安装过程. 安装的是boost_1_60_0. (1)首先去下载最新的boost代码包,网址www.boost.org. (2)进入到自己的目录,解压: bzip2 -d boo ...

  4. Linux下安装和使用boost库

    Linux下安装和使用boost库 2016-08-26 20:29:06 zhaomax 阅读数 349更多 分类专栏: C++ 用boost库中的serialization库.Boost库分为两个 ...

  5. Linux下boost库的编译、安装详解

    1.下载源文件 去官网下载:http://www.boost.org/ 这里下载最新版本 wget https://dl.bintray.com/boostorg/release/1.64.0/sou ...

  6. VS2008下直接安装使用Boost库1.46.1版本号

    Boost库是一个可移植.提供源码的C++库,作为标准库的后备,是C++标准化进程的发动机之中的一个. Boost库由C++标准委员会库工作组成员发起,当中有些内容有望成为下一代C++标准库内容.在C ...

  7. VS2010下安装boost库

    1.去www.boost.org下载最新的boost,我下载了boost_1_46_1.7z 2.(我放在D:/cpp目录下)解压到当前文件夹 3.打开VS2010->VS TOOLS-> ...

  8. linux boost 卸载,Ubuntu下boost库的编译安装步骤及卸载方法详解

    最近由于编译一个程序用到了C++的boost库,所以便安装了这个库.但是,其中遇到了一些小问题.所以记录下来,以供别人参考. 首先说一下我的环境:Ubuntu 12.04 32bit,  gcc 4. ...

  9. Windows下编译和安装Boost库

    因为boost都是使用模板的技术,所以所有代码都是写在一个.hpp头文件中.这样boost中的大部分内容是不需要编译生成相应的链接库,只需要设置下面的包含目录(或者设置一下环境变量),在源文件中包含相 ...

最新文章

  1. mysql等待事件类型_Oracle中常见的33个等待事件小结
  2. centos7配网卡_centos7配置网卡
  3. Docker持续集成与容器管理--系列教程
  4. java与php链条遇到的坑,记一次Java加密加签算法到php的坑
  5. 图片压缩的另一种实现(3)
  6. 计算机丢失faultrep.dll,faultrep.dll
  7. linux 磁盘清理脚本,磁盘清理脚本
  8. 程序设计实践(评注版) 评注者序
  9. angular表单验证
  10. 将Excel(.xlsx)中的数据导入到数据库中
  11. php dom怎么创建节点,前端必须掌握的DOM节点操作方法!
  12. 数学建模线性规划实例及详细解答(MATLAB代码)
  13. jqGrid分页点击事件,点击分页的时候滚动条回到顶端
  14. 计算机画图照片大小,如何压缩图片大小,用电脑系统自带画图工具即可
  15. jquery 移动端 ui 组件库 移动端前端UI库—Frozen UI、SUI Mobile、light7、WeUI、jqweui
  16. windows使用密钥登录linux服务器
  17. 中医大2020年7月网考计算机应用基础,2020年7月网络教育统考《计算机应用基础》Internet应用模拟题试卷2...
  18. 高数 | 为什么f(x)从a到b的积分等于从b到a的积分的相反数?
  19. 项目实战:PB/ORACLE:C/S架构 学生成绩教务管理系统
  20. 2020-05-09 工作中英语单词积累

热门文章

  1. Perl的浅拷贝和深度拷贝
  2. 网络框架 Retrofit(三)
  3. [3/21]Windows Server 2008时钟方面的改进展示
  4. 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.5) 登录功能的实现,完善登录功能...
  5. C#学习笔记(十三):I/O操作
  6. Spring的基本使用
  7. Maven高级之插件开发
  8. MySQL在DOS指令里面的使用以及增删改查的使用
  9. 统计指定目录下的视频时长
  10. postgresql 插入 时间戳_数据也玩躲猫猫?PostgreSQL中别人提交的数据,我为什么看不到?...