boost库下的deadline_timer和steady_timer 区别

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 deadline_timer;
basic_deadline_timer是一个模板类,它的定义如下:

template<
    typename Time,
    typename TimeTraits = boost::asio::time_traits

/// Time traits specialised for posix_time.
template <>
struct time_traits
{
  /// 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 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();

 
 
 
 

你可能感兴趣的:(c++,boost)