7 clock和Timer
- c++11提供一个精度中立的程序库(chrono程序库),定义与
<chrono>
- c++标准库也提供基本的c和posix接口,处理日历时间;
1 chrono程序库简介
目的:
- 希望处理“timer和clock在不同的系统中可能不同”的事实;
- 强化时间精度
- 提供精度中立的概念,将duration(时间段)和timepoint(时间点)从特定的clock区分开来;
chrono程序组成:
- duration(时间段): 某时间单位上的一个明确的tick(片可数)
- timepoint(时间点):一个duration和一个epoch(起始点)的组合;
- timepoint以某个clock为参数;Clock是一个对象,定义了timepoint的起点;
2 duration(时间段)
duration是一个数值(表现tick个数)和一个分数(表现时间单位,以秒计时)的组合;其中分数由ratio描述;
例如:
//默认为秒为单位
std::chrono::duration<int> twentySeconds(20);
//一分钟为单位(60/1)
std::chrono::duration<double,std::ratio<60>> halfAMinute(0.5); //0.5 * 60
//以一毫秒为单位(1/1000)
std::chrono::duration<long,std::ratio<1,1000>> oneMillisecond(1);// 1毫秒
2.1 duration预定义
c++标准库提供的定义:
类型 | 定义 |
---|---|
std::chrono::nanoseconds | duration</*至少 64 位的有符号整数类型*/, std::nano> |
std::chrono::microseconds | duration</*至少 55 位的有符号整数类型*/, std::micro> |
std::chrono::milliseconds | duration</*至少 45 位的有符号整数类型*/, std::milli> |
std::chrono::seconds | duration</*至少 35 位的有符号整数类型*/> |
std::chrono::minutes | duration</*至少 29 位的有符号整数类型*/, std::ratio<60>> |
std::chrono::hours | duration</*至少 23 位的有符号整数类型*/, std::ratio<3600>> |
有了这些定义:
std:: chrono:: seconds twentyseconds(20); //20秒
2.2 duration的算术运算
说明:
- 可以计算两个duration的和,差积商;
- 可以加减两个tick,或者加减其他duration;
- 可以比较两个duration的大小;
主要的地方:
- 运算的两个duration的单位类型可以不同;
- 标准库的common_type<>为duration提供了一个重载版本,因此运算的得到的duration其单位是两个操作的单位的最大公约数;
例如:
chrono::seconds d1(42); //42 秒
chrono::milliseconds d2(10); //10毫秒
//d1- d2的结果为:
//拥有“41990个毫秒单位”的一个duration
- 可以将duration转换为不同的单位,只要彼此之间存在隐式转换;因此,可以将小时转换为秒,反向不行;
2.3 duration的其他操作
说明:
- duration可以进行隐式转换到一个“比较精准的单位类型”:无精度损失
- 隐式转换但是不能转换至“比较粗糙的单位类型”:有精度损失
例如:
1. 将一个42010毫秒转换到秒:42秒,这个duration中的10毫秒丢失了,这是不行的;
2. 但是可以使用duration_cast<>
进行强制转换
std::chrono::seconds sec(55);
std::chrono::minutes m1 = sec; //error
std::chrono::minnutes m2 = std::chrono::duration_cast<std::chrono:::minutes>(sec); //ok
因此,利用强制转换,可以进行将duration切割成不同的单元;
例如:
//---------省略-------------
using namespace std;
using namespace std::chrono;
//--------------省略----------
milliseconds ms(7255042);
hours hh = duration_cast<hours>(ms);
minutes mm = duration_cast<minutes>(ms%hours(1));
seconds ss = duration_cast<seconds>(ms%minutes(1));
milliseconds msec = duration_cast<milliseconds>(ms%seconds(1));
cout << " " << setfill('0') << setw(2) << hh.count() << "::"
<< setw(2) << mm.count() << "::" << setw(2) << ss.count() << "::"
<< setw(2) << msec.count() << endl;
//结果为:
02::00::55::42
说明: 部分vs2013支持部分c++11,不能通过编译,因此需要更新的编译器;
3 clock和Timepoint
timepoint 和clock:
- clock: 定义了一个epoch(起始点)和一个tick周期;
- Timepoint:表现某个特定的时间点,关联到某个clock的某个正值或者负值的duration;
3.1 clock
c++标准库提供了三个clock接口:
system_clock: 所表现的timepoint关联到系统的即时时钟,这个接口提供
to_time_t()
和from_time_t()
两个函数,允许将timepoint和“c类型的系统时间类型”time_t之间转换,意味着可以转换到日历时间;steady_clock: 保证绝对不会被调整;当实际时间流逝的时候,timepoint值不会减少,用来计算时间间隔;
high_resolution_clock: 表现的是当前系统中带有最短tick的clock;它可能是system_clock或stable_clock的同义词。
3.2 Timepoint
3.2.1 time_point的定义
定义为:
template <class Clock, class Duration = typename Clock::duration>
class time_point;
四个特定的timepoint:
- Epoch: 由任何clock的time_point的默认构造函数产出;
- Current time: 由任何的clock的static成员函数now()产出;
- Minimum timepoint: 由任何clock的time_point的static成员函数min()产生;
- Maximum timepoint: 由任何clock的time_point的static成员函数max()产出;
例子:
#include <chrono>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace std::chrono;
string asString (const chrono::system_clock::time_point & tp)
{
time_t t = chrono::system_clock::to_time_t(tp);
string ts = ctime(&t);
return ts;
}
int main(){
chrono::system_clock::time_point tp;
cout<<"epoch: "<<asString(tp) ;
tp = chrono::system_clock::now();
cout<<"now: "<<asString(tp);
//tp = chrono::system_clock::time_point::min();
//cout<<"min: "<<asString(tp);
//tp = chrono::system_clock::time_point::max();
//cout<<"max: "<<asString(tp);
}
min()和max()出错,不知道哪里有问题!
输出为:
epoch: Thu Jan 01 08:00:00 1970
now: Thu Aug 31 11:20:44 2017
说明:
- 只有system_clock才有接口从time_point转到time_t类型;
3.2.2 time_point的 操作
4 C和posix提供的Date/Time函数
- C语言以供的接口在
<time.h>
,现在位于c++<ctime>
中;
4.1 ctime中的预定义
说明:
- time_t通常只是“始于unix epoch(1970年1月1日)的秒数;”
4.1.2 类型成员
- clock_t
- size_t
- time_t
- struct tm
结构体 tm的成员:
int tm_sec //秒 在minute后 – [0, 60][note 1]
int tm_min //分钟,在1小时后 - [0,59]
int tm_hour //小时,自午夜开始 - [0,23]
int tm_mday //月的一天 - [1,31]
int tm_mon //1月,0开始 - [0,11]
int tm_year //年,自1900年以来
int tm_wday //自上周日以来- [0,6]
int tm_yday //天,自1月1日 - [0,365]
int tm_isdst //夏令时间标志。大于0表示夏令时,如果夏令时没有效果,则为零,如果信息不可用,小于零。
(公开成员对象)
5 以计时器停滞线程
duration和timepoint可以用来停滞线程或者程序;
例如:
- sleep_for()和sleep_until():由this_thread提供的来停滞线程;
- try_lock_for()和try_lock_until(),用来等待一个mutex时指定最大时间段;
- wait_for()和wait_until(),用来等待某条件成立或等待一个future时指定最大时间段;
说明:
- 所有以..for()结束的停滞函数需要一个duration
- 所有以..until()结束的停滞函数需要一个timepoint
- 这些timer都不保证绝对精准
例子:
this_thread::sleep_for(chrono::seconds(10)); //停滞当前线程10秒
this_thread::sleep_until(chrono:system_clock::now() + chrono::seconds(10) ) ; //停滞当前线程直到system_clock来到比当前多10秒的timepoint