最近代码中需要用到时间功能,来判断某些操作是否超时未完成,发现C++11里面提供了时间类,自己摸索一下,写一篇文档分享心得体会,下文都是自己的理解。
std::chrono::duration
std::chrono::duration
,进入源码中可以看到它是:需要用两个参数组合而成
template<class _Rep,class _Period>
class duration
顾名思义:duration
的意思是期间(周期次数与一个周期时间的结合),这个模板有两个参数,第一个是_Period
,把它理解为周期,一个周期需要的时间单位,当然你也可以理解它为精度,分辨率。第二个是_Rep
,我把他理解为一个重复次数或者说是数值,表示这个周期需要执行多少个单位。所以这个duration
就通过_Rep
*_Period
,得到了这个期间的时长。当我们需要定义一个期间时,就可以先定义最小颗粒度的单位(即_Period,一个周期时间),再定义需要执行的周期次数(_Rep),则可以完成我们需要的周期。
给两个栗子:下面这两个表示方式都表示十秒钟
std::chrono::duration<int, std::ratio<1, 1>> ten_secends(10); //十秒钟
std::chrono::duration<int, std::ratio<10,1>> ten_secends(1); //十秒钟
_Period
使用ratio
实例化模板类_Period,ratio
理解为精度,我把它理解为一个时间周期的意思。他的模板参数如下
template<intmax_t _Nx, intmax_t _Dx = 1>
struct ratio
使用两个整型进行初始化,_Nx
表示分子,_Dx
表示分母,ratio<1,1>
表示一秒钟的时间周期,C++标准中给我们定义了很多个ratio
的初始化结构。我们可以在程序中直接使用,std::milli
等精度。
按照上面我所说,我们的duration
期间,是通过两个参数组成,ratio
是其一,其二就是一个重复的次数_Rep
,基于生活中的习惯,C++chrono库中已经给我们typedef了常见的期间。
如上图所示,给我们定义了纳秒,微妙,秒,分钟,小时等,我也不知道啥单位了。我们使用的时候就可以这样
std::chrono::seconds twenty_secends(20); //20秒
std::chrono::minutes twenty_min(20); //20分钟
std::chrono::hours twenty_hour(20); //20小时
其实duration
的第一个参数_Rep
不止于int
类型,当你想表示0.5秒时,你也可以试试以下的用法。
std::chrono::duration<double> halfSecs(0.5); //默认参数ratio<1,1>
std::chrono::duration<int, std::milli> halfSecs(500);
std::duration
为我们提供了count
函数,返回的是_Rep在此_Period下的值,比如:
std::chrono::seconds secend_one(1);
std::cout << "秒数 : " << secend_one.count() << std::endl; //在秒下的值
std::chrono::milliseconds mill_one = std::chrono::duration_cast<std::chrono::milliseconds>(secend_one);
std::cout << "毫秒数 : " << mill_one.count() << std::endl; //转换成毫秒后的值
小结std::duration
其实很简单,由数量和单位组成,就好比10只,10是数量,只是单位。只要确定数量和单位,就可以定义出一个自己需要的期间了。
std::system_clock
system_clock
提供了三个方法now
,to_time_t
,from_time_t
。
typedef chrono::time_point<system_clock> time_point
,实例化了系统时间的time_point
system_clock::now
函数得到桌面右下角windows的系统时间,你右下角的时间是多少,它就得到的是什么,会被人为的修改后,得到不正确的时间。
to_time_t
,将得到的time_point,转换成time_t结构。from_time_t
代码如下:
#include <chrono>
#include <iostream>
int main()
{
std::chrono::system_clock::time_point tp = std::chrono::system_clock::now(); //得到系统时间
time_t tt = std::chrono::system_clock::to_time_t(tp); //将系统时间time_point 转化为time_t格式
std::string strTime = ctime(&tt); //将time_t转换成字符串
std::cout << strTime.c_str() << std::endl;
return 0;
}
std::steady_clock
在上面的std::syste_clock
中,我们知道这个时间是可以被人为的修改的,如果我们需要一个用户无法更改的时间时,std::steady_clock
给我们提供了帮助,它提供一个相对于boot启动后到当前的时间,如果我们需要计算一件事情做了多长时间,std::steady_clock
充当绝对主力。
std::chrono::steady_clock::now()
提供了boot启动到当前的时间time_point。
#include <chrono>
#include <iostream>
#include <thread>
int main()
{
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); //得到开始时间点
std::this_thread::sleep_for(std::chrono::seconds(1)); //做事情
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); //得到结束时间点
std::cout << (std::chrono::time_point_cast<std::chrono::seconds>(end) -
std::chrono::time_point_cast<std::chrono::seconds>(start)).count() << std::endl; //相对时间计算
return 0;
}
time_point
为我们提供了time_since_epoch
方法,返回一个std::duration
,在system_clock
表示从1970年1月1日到现在经历的时间。steady_clock
中,表示boot打开到现在经历的时间。调用count
得到duration里面的值。
#include <chrono>
#include <iostream>
int main()
{
std::chrono::system_clock::time_point system_clocktp = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::hours>(system_clocktp.time_since_epoch()).count() << std::endl;
std::chrono::steady_clock::time_point steady_clocktp = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::hours>(steady_clocktp.time_since_epoch()).count() << std::endl;
return 0;
}
小结:在计算某个任务相对时间时,使用steady_clock
是比较合适的,不会受到更改了系统时间而影响。如果使用了system_clock
,在执行任务时,用户更改了系统时间,则下次调用就会出现时间异常等问题。