引入
- 在过去,C和POSIX提供的系统时间接口,允许从秒转换至毫秒,再至微秒,最终至纳秒,问题是每次转换就需要一个新接口
- 基于这个原因,C++11开始提供一个精度中立的程序库,称为chrono程序库,被定义于<chrono>中
概述
- Chrono程序库的设计,是希望能够处理“timer和clock在不同系统中可能不同”的事实,同时也是为了强化实践精准度
- 为了避免像POSIX的time程序库那样每十年就引入一个新的时间类型,C++标准库的目标是提供一个精度中立概念,把duration(时间段)和timepoint(时间点)从特定clock(时钟)区分开来。最终结果就是chrono程序库核心由以下类型或概念组成:
- Chrono程序库定义在<chrono>头文件中,命名空间为namespace std::chrono
Duration
辅助类型
构造函数
#include <chrono>
int main()
{
// 方法1:手动指定单位(基本不用)
std::chrono::duration<int> twentySeconds(20); // 20*1秒=20秒(以秒为单位)
std::chrono::duration<double, std::ratio<60>> halfAMinute(0.5); // 0.5*60秒=0.5分钟(以分钟为单位(60/1))
std::chrono::duration<long, std::ratio<1, 1000>> oneMillisecond(1); //1*0.001秒=1毫秒(以毫秒为单位(1/1000))
// 内置定义
std::chrono::seconds twentySeconds(20); //20秒
std::chrono::hours aDay(24); //24小时
std::chrono::milliseconds oneMillisecond(1); //1毫秒
// 错误: treat_as_floating_point<int>::value == false,
// 此时长只允许整数计次
// std::chrono::duration<int, std::kilo> d3(3.5);
// 使用小数计次的 30Hz 钟
std::chrono::duration<double, std::ratio<1, 30>> hz30(3.5);
// 从 3 毫秒构造 3000 微秒
std::chrono::microseconds us = ms;
// error: 1/1000000 is not divisible by 1/1000
// std::chrono::milliseconds ms2 = us
std::chrono::duration<double, std::milli> ms2 = us; // 3.0 毫秒
}
count
作用:返回此 duration 的嘀嗒数。
#include <chrono>
#include <iostream>
int main()
{
std::chrono::milliseconds ms{3}; // 3 毫秒
// 从 3 毫秒构造 6000 微秒
std::chrono::microseconds us = 2*ms;
// 使用分数计次的 30Hz 时钟
std::chrono::duration<double, std::ratio<1, 30>> hz30(3.5);
std::cout << "3 ms duration has " << ms.count() << " ticks\n"
<< "6000 us duration has " << us.count() << " ticks\n"
<< "3.5 30Hz duration has " << hz30.count() << " ticks\n";
}
运算
运算所涉及的两个duration的单位类型可以不同,返回值单位将是两个操作数的单位的最大公约数
- 演示案例:
std::chrono::seconds d1(42); //42秒
std::chrono::milliseconds d2(10); //10毫秒
d1 - d2; //返回41990个毫秒为单位的一个duration,42000-10=41990
d1 < d2; //返回false
- 演示案例:
std::chrono::duration<int, std::ratio<1, 3>> d1(1); //1/3秒
std::chrono::duration<int, std::ratio<1, 5>> d2(1); //1/5秒
d1 + d2; //返回8/15秒,1/3+1/5=8/15
d1 < d2; //返回false
- 你也可以将duration转换为不同的单位,只要彼此之间存在隐式转换即可。因此,你可以将小时转换为秒,但是反向不可以(详情还可以见duration_cast<>()的介绍)。例如:
std::chrono::seconds twentySeconds(20); //20分钟
std::chrono::hours aDay(24); //24消失
std::chrono::milliseconds ms; //0毫秒
ms += twentySeconds + aDay; //86400000毫秒
--ms; //86399999毫秒
ms *= 2; //172839998毫秒
std::cout << ms.count() << " ms" << std::endl; // 172839998ms
std::cout << std::chrono::nanoseconds(ms).count() << " ns" << std::endl; //172839998000000 ns
- 演示案例:
template<typename V,typename R>
std::ostream& operator<<(std::ostream& s, const std::chrono::duration<V, R>& d)
{
s << "[" << d.count() << " of " << R::num << "/" << R::den << "]";
return s;
}
int main()
{
std::chrono::milliseconds d(42);
std::cout << d << std::endl;
duration_cast
- 在上面我们介绍过duration的类型转换,可以将一个低精度的单位类型转换为一个高精度的单位类型(例如,将分钟转换为秒,将秒转换为微秒),但是不能将一个高精度的单位类型转换为一个低精度的单位类型(例如,将微秒转换为秒,将秒转换为分钟等。因为这可能会造成数据的丢失,例如将42010毫秒转换为秒,结果是42,那么原本的10毫秒就丢失了)
- 如果想要将高精度的单位类型转换为一个低精度的单位类型,那么可以使用duration_cast<>进行强制转换
std::chrono::seconds sec(55);
//错误的,默认不能将秒转换为分钟
std::chrono::minutes m1 = sec;
//正确的,可以使用duration_cast,将秒转换为分钟
std::chrono::minutes m2 = std::chrono::duration_cast<std::chrono::minutes>(sec);
- 将浮点数类型的duration转换为整数类型的duration也需要使用duration_cast<>。例如:
std::chrono::duration<double, std::ratio<60>> halfMin(0.5);
//错误,halfMin的tick为double类型,s1的tick默认为int类型
std::chrono::seconds s1 = halfMin;
//正确,使用duration_cast强制转换
std::chrono::seconds s2 = std::chrono::duration_cast<std::chrono::seconds>(halfMin);
- 演示案例:
#include <iostream>
#include <chrono>
#include <ratio>
#include <thread>
void f()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main()
{
auto t1 = std::chrono::high_resolution_clock::now();
f();
auto t2 = std::chrono::high_resolution_clock::now();
// 整数时长:要求 duration_cast
auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
// 小数时长:不要求 duration_cast
std::chrono::duration<double, std::milli> fp_ms = t2 - t1;
std::cout << "f() took " << fp_ms.count() << " ms, "
<< "or " << int_ms.count() << " whole milliseconds\n";
}
#include <chrono>
#include <iostream>
int main()
{
// 简单算术
std::chrono::seconds s = std::chrono::hours(1)
+ 2*std::chrono::minutes(10)
+ std::chrono::seconds(70)/10;
std::cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
// 时长除以一个数和时长除以另一时长的区别
std::cout << "Dividing that by 2 minutes gives "
<< s / std::chrono::minutes(2) << '\n';
std::cout << "Dividing that by 2 gives "
<< (s / 2).count() << " seconds\n";
// 余数运算符在确定此特定时长在时间框架的场合有用,
// 例如,拆分它为时、分和秒:
std::cout << s.count() << " seconds is "
<< std::chrono::duration_cast<std::chrono::hours>(s).count() << " hours, "
<< std::chrono::duration_cast<std::chrono::minutes>(s % std::chrono::hours(1)).count() << " minutes, "
<< std::chrono::duration_cast<std::chrono::seconds>(s % std::chrono::minutes(1)).count() << " seconds\n";
}
比较大小
#include <chrono>
#include <iostream>
int main()
{
if(std::chrono::seconds(2) == std::chrono::milliseconds(2000))
std::cout << "2 s == 2000 ms\n";
else
std::cout << "2 s != 2000 ms\n";
if(std::chrono::seconds(61) > std::chrono::minutes(1))
std::cout << "61 s > 1 min\n";
else
std::cout << "61 s <= 1 min\n";
}