[原]C++新标准之std::chrono::duration

概览

c++新标准提供了新的线程库,最近在写测试代码的时候需要让当前线程休眠,之前直接调用windows提供的Sleep()就好了,新标准中可以使用std::this_thread::sleep_for()或者std::this_thread::sleep_until()
来实现休眠。其中涉及到了std::chrono::durationstd::chrono::time_point。本篇只总结std::chrono::durationstd::chrono::time_point会再写一篇总结。

std::chrono::duration

描述

std::chrono::duration定义在文件中,用来表示一个时间段。

cppreference上的原话如下:

Class template std::chrono::duration represents a time interval.
It consists of a count of ticks of type Rep and a tick period, where the tick period is a compile-time rational constant representing the number of seconds from one tick to the next.
The only data stored in a duration is a tick count of type Rep. If Rep is floating point, then the duration can represent fractions of ticks. Period is included as part of the duration's type, and is only used when converting between different durations.

Rep参数代表了可以传入的时间单位的类型,可以为float, int, int64等等,如果为float表示可以传入时间单位的一部分,比如传入1.2表示1.2倍个时间单位
Period参数代表了时间单位,可以为微秒,毫秒,秒,分钟,小时等(或者其它自定义的单位,类型为std::ratio)。

注:

  1. 上文中的tick可以理解为周期,或时间单位。
  2. the number of seconds 表示是周期值基于秒来计算的。

类定义

std::chrono::duration是一个模板类,关键代码摘录如下(格式有调整):

  1. template<class _Rep, class _Period> 
  2. class duration { 
  3. public
  4. typedef duration<_Rep, _Period> _Myt; 
  5. typedef _Rep rep; 
  6. typedef _Period period; 
  7.  
  8. // constructor, save param to _MyRep, used by count() member function. 
  9. template<class _Rep2, 
  10. class = typename enable_if<is_convertible<_Rep2, _Rep>::value 
  11. && (treat_as_floating_point<_Rep>::value || !treat_as_floating_point<_Rep2>::value), 
  12. void>::type> 
  13. constexpr explicit duration(const _Rep2& _Val) 
  14. : _MyRep(static_cast<_Rep>(_Val)) 
  15.  
  16. constexpr _Rep count() const { return (_MyRep); } 
  17. }; 
  18.  
  19. // convert duration from one unit to another. 
  20. template<class _To, class _Rep, class _Period> inline 
  21. constexpr typename enable_if<_Is_duration<_To>::value, _To>::type 
  22. duration_cast(const duration<_Rep, _Period>& _Dur) 
  23. typedef ratio_divide<_Period, typename _To::period> _CF; 
  24.  
  25. typedef typename _To::rep _ToRep; 
  26. typedef typename common_type<_ToRep, _Rep, intmax_t>::type _CR; 
  27.  
  28. #pragma warning(push) 
  29. #pragma warning(disable: 6326) // Potential comparison of a constant with another constant. 
  30. return (_CF::num == 1 && _CF::den == 1 
  31. ? static_cast<_To>(static_cast<_ToRep>(_Dur.count())) 
  32. : _CF::num != 1 && _CF::den == 1 
  33. ? static_cast<_To>(static_cast<_ToRep>( 
  34. static_cast<_CR>( 
  35. _Dur.count()) * static_cast<_CR>(_CF::num))) 
  36. : _CF::num == 1 && _CF::den != 1 
  37. ? static_cast<_To>(static_cast<_ToRep>( 
  38. static_cast<_CR>(_Dur.count()) 
  39. / static_cast<_CR>(_CF::den))) 
  40. : static_cast<_To>(static_cast<_ToRep>( 
  41. static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) 
  42. / static_cast<_CR>(_CF::den)))); 
  43. #pragma warning(pop) 

duration_cast()分析

函数duration_cast()提供了在不同的时间单位之间进行转换的功能。

duration_cast()主要分为两部分:

  • 通过ratio_divide定义了从一个ratio转换到另外一个ratio的转换比例。
    比如1/102/5的转换比例是1/4 ((1/10/(2/5)) = 1/4),也就是说一个1/10相当于1/42/5
    对应到代码里就是_CF::num = 1, _CF::den = 4.

  • 根据转换比例把n个单位的原数据转换到目标数据(return语句)
    return语句写的这么复杂是为了效率,避免不必要的乘除法,当分子是1的时候没必要乘,当分母是1的时候没必要除。
    简化一下(去掉了强制类型转换)就是:
    return _Dur.count() * (_CF::num / _CF::den);

通俗点讲:如果AB的转换比例是num/den,那么1A可以转换为num/denB, nA可以转换为 n * (num/den)B

注:vs自带的源码真心不易读,推荐参考boost源码。

预定义的duration

vs为了写代码方便,预定义了几个常用的时间单位,摘录如下:

  1. typedef duration<long long, nano> nanoseconds; // 纳秒 
  2. typedef duration<long long, micro> microseconds; // 微秒 
  3. typedef duration<long long, milli> milliseconds; // 毫秒 
  4. typedef duration<long long> seconds; // 秒 
  5. typedef duration<int, ratio<60> > minutes; // 分钟 
  6. typedef duration<int, ratio<3600> > hours; // 小时 

根据以上定义我们可以发现std::chrono::microseconds定义中的Rep的类型是long longPeriod类型是milli

注:因为std::chrono::microseconds定义中的Rep的类型是long long, 我们不能通过如下方法来休眠100.5毫秒std::this_thread::sleep_for(std::chrono::microseconds(100.5));,类型不匹配,会报编译错误。如果想休眠100.5毫秒,我们可以这么写:
std::this_thread::sleep_for(std::chrono::duration<float, std::milli>(100.5f));

示例代码

例1:分钟转换为毫秒

  1. #include <iostream> 
  2. #include <chrono> 
  3. int main() 
  4. std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::minutes(3)); 
  5. std::cout << "3 minutes equals to " << ms.count() << " milliseconds\n"
  6. std::cin.get(); 

例2. 自定义单位转换

  1. #include <iostream> 
  2. #include <chrono> 
  3.  
  4. typedef std::chrono::duration<float, std::ratio<3, 1> > three_seconds; 
  5. typedef std::chrono::duration<float, std::ratio<1, 10> > one_tenth_seconds; 
  6.  
  7. int main() 
  8. three_seconds s = std::chrono::duration_cast<three_seconds>(one_tenth_seconds(3)); 
  9. std::cout << "3 [1/10 seconds] equal to " << s.count() << " [3 seconds]\n"
  10. std::cin.get(); 

例3. 休眠100毫秒

  1. #include <thread> 
  2. #include <chrono> 
  3. int main() 
  4. std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
  5. // or 
  6. std::this_thread::sleep_for(std::chrono::duration<long long, std::milli>(100)); 
  7. // or  
  8. // typedef ratio<1, 1000> milli; 
  9. std::this_thread::sleep_for(std::chrono::duration<long long, std::ratio<1, 1000> >(100)); 

参考资料

posted @ 2018-08-14 23:09  BCN  阅读(26781)  评论(0编辑  收藏  举报