C++11一些常用的特性(多线程)
一、处理日期和时间的 chrono 库
C++11 中提供了日期和时间相关的库 chrono,通过 chrono 库可以很方便地处理日期和时间,为程序的开发提供了便利。chrono 库主要包含三种类型的类:时间间隔duration、时钟clocks、时间点time point。
1. 时间间隔 duration
1.1 常用类成员
duration表示一段时间间隔,用来记录时间长度,可以表示几秒、几分钟、几个小时的时间间隔。duration 的原型如下:
// 定义于头文件 <chrono>
template<
class Rep,
class Period = std::ratio<1>
> class duration;
Rep:这是一个数值类型,表示时钟数(周期)的类型(默认为整形)。若 Rep 是浮点数,则 duration 能使用小数描述时钟周期的数目。
Period:表示时钟的周期,它的原型如下:
// 定义于头文件 <ratio>
template<
std::intmax_t Num,
std::intmax_t Denom = 1
> class ratio;
ratio 类表示每个时钟周期的秒数,其中第一个模板参数 Num代表分子,Denom代表分母,该分母值默认为 1,因此,ratio代表的是一个分子除以分母的数值,比如:ratio<2> 代表一个时钟周期是 2 秒,ratio<60 > 代表一分钟,ratio<6060 > 代表一个小时,ratio<6060*24 > 代表一天。而 ratio<1,1000 > 代表的是 1/1000 秒,也就是 1 毫秒,ratio<1,1000000 > 代表一微秒,ratio<1,1000000000 > 代表一纳秒。
为了方便使用,在标准库中定义了一些常用的时间间隔,比如:时、分、秒、毫秒、微秒、纳秒,它们都位于 chrono 命名空间下,定义如下:
纳秒:std::chrono::nanoseconds duration<Rep*/* 至少 64 位的有符号整数类型 /, std::nano>
微秒:std::chrono::microseconds duration<Rep*/* 至少 55 位的有符号整数类型 /, std::micro>
毫秒:std::chrono::milliseconds duration<Rep*/* 至少 45 位的有符号整数类型 /, std::milli>
秒: std::chrono::seconds duration<Rep*/* 至少 35 位的有符号整数类型 />
分钟:std::chrono::minutes duration<Rep*/* 至少 29 位的有符号整数类型 /, std::ratio<60>>
小时:std::chrono::hours duration<Rep*/* 至少 23 位的有符号整数类型 /, std::ratio<3600>>
注意:到 hours 为止的每个预定义时长类型至少涵盖 ±292 年的范围。
duration 类的构造函数原型如下:
// 1. 拷贝构造函数
duration( const duration& ) = default;
// 2. 通过指定时钟周期的类型来构造对象
template< class Rep2 >
constexpr explicit duration( const Rep2& r );
// 3. 通过指定时钟周期类型,和时钟周期长度来构造对象
template< class Rep2, class Period2 >
constexpr duration( const duration<Rep2,Period2>& d );
为了更加方便的进行 duration 对象之间的操作,类内部进行了操作符重载:
operator= 赋值内容 (公开成员函数)
operator+
operator- 实现一元 + 和一元 - (公开成员函数)
operator++
operator++(int)
operator–
operator–(int) 递增或递减周期计数 (公开成员函数)
operator+=
operator-=
operator*=
operator/=
operator%= 实现二个时长间的复合赋值 (公开成员函数)
duration 类还提供了获取时间间隔的时钟周期数的方法 count (),函数原型如下:
constexpr rep count() const;
1.2 类的使用
通过构造函数构造事件间隔对象示例代码如下:
#include <chrono>
#include <iostream>
using namespace std;
int main()
{
chrono::hours h(1); // 一小时
chrono::milliseconds ms{ 3 }; // 3 毫秒
chrono::duration<int, ratio<1000>> ks(3); // 3000 秒
// chrono::duration<int, ratio<1000>> d3(3.5); // error
chrono::duration<double> dd(6.6); // 6.6 秒
// 使用小数表示时钟周期的次数
chrono::duration<double, std::ratio<1, 30>> hz(3.5);
}
h(1) 时钟周期为 1 小时,共有 1 个时钟周期,所以 h 表示的时间间隔为 1 小时
ms(3) 时钟周期为 1 毫秒,共有 3 个时钟周期,所以 ms 表示的时间间隔为 3 毫秒
ks(3) 时钟周期为 1000 秒,一共有三个时钟周期,所以 ks 表示的时间间隔为 3000 秒
d3(3.5) 时钟周期为 1000 秒,时钟周期数量只能用整形来表示,但是此处指定的是浮点数,因此语法错误
dd(6.6) 时钟周期为默认的 1 秒,共有 6.6 个时钟周期,所以 dd 表示的时间间隔为 6.6 秒
hz(3.5) 时钟周期为 1/30 秒,共有 3.5 个时钟周期,所以 hz 表示的时间间隔为 1/30*3.5 秒
chrono 库中根据 duration 类封装了不同长度的时钟周期(也可以自定义),基于这个时钟周期再进行周期次数的设置就可以得到总的时间间隔了(时钟周期 * 周期次数 = 总的时间间隔)。
示例代码如下:
#include <chrono>
#include <iostream>
int main()
{
std::chrono::milliseconds ms{3}; // 3 毫秒
std::chrono::microseconds us = 2*ms; // 6000 微秒
// 时间间隔周期为 1/30 秒
std::chrono::duration<double, std::ratio<1, 30>> hz(3.5);
std::cout << "3 ms duration has " << ms.count() << " ticks\n"
<< "6000 us duration has " << us.count() << " ticks\n"
<< "3.5 hz duration has " << hz.count() << " ticks\n";
}
输出的结果为:
3 ms duration has 3 ticks
6000 us duration has 6000 ticks
3.5 hz duration has 3.5 ticks
ms 时间单位为毫秒,初始化操作 ms{3} 表示时间间隔为 3 毫秒,一共有 3 个时间周期,每个周期为 1 毫秒
us 时间单位为微秒,初始化操作 2ms 表示时间间隔为 6000 微秒,一共有 6000 个时间周期,每个周期为 1 微秒
hz 时间单位为秒,初始化操作 hz(3.5) 表示时间间隔为 1/303.5 秒,一共有 3.5 个时间周期,每个周期为 1/30 秒
由于在 duration 类内部做了操作符重载,因此时间间隔之间可以直接进行算术运算,比如我们要计算两个时间间隔的差值,就可以在代码中做如下处理:
#include <iostream>
#include <chrono>
using namespace std;
int main()
{
chrono::minutes t1(10);
chrono::seconds t2(60);
chrono::seconds t3 = t1 - t2;
cout << t3.count() << " second" << endl;
}
程序输出的结果:
540 second
在上面的测试程序中,t1 代表 10 分钟,t2 代表 60 秒,t3 是 t1 减去 t2,也就是 60*10-60=540,这个 540 表示的时钟周期,每个时钟周期是 1 秒,因此两个时间间隔之间的差值为 540 秒。
注意事项:duration 的加减运算有一定的规则,当两个 duration 时钟周期不相同的时候,会先统一成一种时钟,然后再进行算术运算,统一的规则如下:假设有 ratio<x1,y1> 和 ratio<x2,y2 > 两个时钟周期,首先需要求出 x1,x2 的最大公约数 X,然后求出 y1,y2 的最小公倍数 Y,统一之后的时钟周期 ratio 为 ratio<X,Y>。
#include <iostream>
#include <chrono>
using namespace std;
int main()
{
chrono::duration<double, ratio<9, 7>> d1(3);
chrono::duration<double, ratio<6, 5>> d2(1);
// d1 和 d2 统一之后的时钟周期
chrono::duration<double, ratio<3, 35>> d3 = d1 - d2;
}
对于分子 6,、9 最大公约数为 3,对于分母 7、5 最小公倍数为 35,因此推导出的时钟周期为 ratio<3,35>
2. 时间点 time point
chrono 库中提供了一个表示时间点的类 time_point,该类的定义如下:
// 定义于头文件 <chrono>
template<
class Clock,
class Duration = typename Clock::duration
> class time_point;
它被实现成如同存储一个 Duration 类型的自 Clock 的纪元起始开始的时间间隔的值,通过这个类最终可以得到时间中的某一个时间点。
Clock:此时间点在此时钟上计量
Duration:用于计量从纪元起时间的 std::chrono::duration 类型
time_point 类的构造函数原型如下:
// 1. 构造一个以新纪元(epoch,即:1970.1.1)作为值的对象,需要和时钟类一起使用,不能单独使用该无参构造函数
time_point();
// 2. 构造一个对象,表示一个时间点,其中d的持续时间从epoch开始,需要和时钟类一起使用,不能单独使用该构