chrono_time_point (三)
文章目录
- chrono_time_point (三)
- 模板参数
- 源码解析
- 构造函数:
- 成员函数time_since_epoch()
- 例子
- timepoint提供的操作
- timepoint的溢出
- C和POSIX提供的Date/Time函数
- 演示案例(timepoint和日历时间的转换)
- 以计时器停滞线程
- this_thread::sleep_until,用于将线程休眠直到某个时刻:
- this_thread::sleep_for,用于将当前线程休眠多长时间:
模板参数
template <class Clock, class Duration = typename Clock::duration>
class time_point;
std::chrono::time_point 表示一个具体时间,如上个世纪80年代、今天下午3点、火车出发时间等,只要它能用计算机时钟表示。
- 第一个模板参数Clock用来指定所要使用的时钟(标准库中有三种时钟,system_clock,steady_clock和high_resolution_clock。见4时钟详解),第二个模板函数参数用来表示时间的计量单位(特化的std::chrono::duration<> )
- 时间点都有一个时间戳,即时间原点。chrono库中采用的是Unix的时间戳1970年1月1日 00:00。所以time_point也就是距离时间戳(epoch)的时间长度(duration)。
源码解析
关键代码摘录如下(格式有调整):
template<class _Clock, class _Duration = typename _Clock::duration>
class time_point
{
public:
typedef _Clock clock;
typedef _Duration duration;
constexpr time_point() : _MyDur(_Duration::zero()) {}
constexpr explicit time_point(const _Duration& _Other) : _MyDur(_Other) {}
template<class _Duration2,
class = typename enable_if<is_convertible<_Duration2, _Duration>::value,void>::type>
constexpr time_point(const time_point<_Clock, _Duration2>& _Tp) : _MyDur(_Tp.time_since_epoch()) {}
constexpr _Duration time_since_epoch() const { return (_MyDur); }
private:
_Duration _MyDur; // duration since the epoch
}
注明:time_point要求其_Clock模板参数必须满足Clock的要求。
- time_point的实现很简单,使用Duration类型的成员变量存储时间,make sense!
- 仔细想想,时间点不就是从0时刻开始经过一定时间间隔的某一个时刻吗?
构造函数:
(1) | time_point(); //默认构造函数,时间戳作为其值 |
---|---|
(2) | template <class Duration2> time_point (const time_point<clock,Duration2>& tp); //拷贝构造函数 |
(3) | explicit time_point (const duration& dtn); //使用duration构造,就是距离时间戳的时间长度 |
成员函数time_since_epoch()
时间点有个重要的函数:duration time_since_epoch() (用于获取当前时间点距离时间戳的时间长度)
例子
即经常用来得到当前时间点到1970年1月1日00:00的时间距离、该函数返回的duration的精度和构造time_point的时钟(Clock)有关(见4时钟详解)。
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std;
int main()
{
//距离时间戳2两秒
chrono::time_point<chrono::system_clock, chrono::seconds> tp(chrono::seconds(2));
cout << "to epoch : " <<tp.time_since_epoch().count() << "s" <<endl;
//转化为ctime,打印输出时间点
time_t tt = chrono::system_clock::to_time_t(tp);
char a[50];
ctime_s(a, sizeof(a), &tt);
cout << a;
system("pause");
return 0;
}
timepoint提供的操作
- timepoint提供的操作如下:
timepoint的溢出
- 虽然timepoint的接口用了ratio,这确保了duration单元的溢出会导致编译器报错,但是duration的溢出还是可能会发生
- 见下面的例子:
- 这也说明了chrono是一个duration/timepoint程序库,而不是个date/time程序库。你可以计算duration和timepoint但仍然必须把epoch、最小和最大的timepoint、闰年和闰秒纳入考虑
C和POSIX提供的Date/Time函数
- **C和POSIX提供的Date/Time函数介绍参阅:**https://blog.csdn.net/qq_41453285/article/details/102651298
- *C++标准也提供了C和POSIX所提供的“处理date和time”接口*。原本在<time.h>内的宏、类型、函数,现在被定义在的namespace std内
- 所提供的操作如下图所示:
- 宏CLOCK_PER_SEC定义了clock()的单位类型(它返回的是elapsed CPU time,以1/CLOCK_PER_SEC秒计)
- time_t通常只是“始自UNIX epoch(1970年1月1日)的秒数”。然而根据C和C++标准的说法,也并不保证如此
演示案例(timepoint和日历时间的转换)
以计时器停滞线程
-
Duration和timepoint可用于线程或程序(即主线程)的停滞(block)。停滞可以是无条件的,也可以指定最大时间段,或等待一个lock或某条件成立,或等待另一线程结束
-
提供的操作如下:
- **sleep_for()和sleep_until():**由this_thead提供用以停滞线程
- **try_lock_for()和try_lock_until():**用来在等待一个mutex时指定最大时间段
- wait_for()和wait_until():用来在等待某条件成立或等待一个future时指定最大时间段
-
所有以…for()结尾的函数都会用到一个duration,所有以…until()结束的函数都会用到一个timepoint
。例如:
- this_thread::sleep_for(chrono::seconds(10)); //会停滞当前线程(不无可能是主线程)10秒钟
- this_thread::sleep_until(chrono::system_clock::now()+chrono::seconds(10)); //停滞当前线程,直到system clock 来到一个“比此刻多10秒”的timepoint
-
这些调用虽然看起来相同,其实不然:
- *所有…until()函数,你需要传递一个timepoint,而它收到时间调整的影响*。如果sleep_until()之后的10秒内system clock被调整了,停滞时间也会被相应调整。例如我们把system clock回调1小时,这个程序将被停滞60分钟又10秒。又如果我们把clock调快超过10秒,timer会立刻结束
- 如果使用…for()函数如sleep_for(),你必须传一个duration,或你使用steady_clock,那么system clock的调整通常不会影响duration。然而在一个不提供steady clock的硬件上,软件平台没机会在不受到“可能被调整的system time”的影响下计算秒数,因此时间的调整也会冲击…for()函数
-
所有这些timer都不会保证绝对精准。对任何timer而言都存在一点点延迟,因为系统只是周期性地检查那个timer结束了,而timer和interrupt(中断)的处理又需要花费一些时间。因此,timer的时间长度将会是它们所指定的时间加上一小段(取决于实现的质量和当下情势)
this_thread::sleep_until,用于将线程休眠直到某个时刻:
#include <iostream>
#include <chrono>
#include <thread>
auto now() { return std::chrono::steady_clock::now(); }
auto awake_time() {
using std::chrono::operator""ms;
return now() + 2000ms;
}
int main()
{
std::cout << "Hello, waiter...\n" << std::flush;
const auto start {now()}; //获取当前时间
std::this_thread::sleep_until(awake_time()); //当前线程睡眠直到当前时刻的2000ms后
std::chrono::duration<double, std::milli> elapsed {now() - start}; //线程唤醒,计算时差
std::cout << "Waited " << elapsed.count() << " ms\n";
return 0;
}
运行程序输出:
Hello, waiter...
Waited 1999.28 ms
this_thread::sleep_for,用于将当前线程休眠多长时间:
#include <iostream>
#include <chrono>
#include <thread>
int main()
{
using namespace std::chrono_literals;
std::cout << "Hello waiter\n" << std::flush;
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(2000ms);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << "Waited " << elapsed.count() << " ms\n";
return 0;
}
运行程序输出:
Hello waiter
Waited 2000.07 ms
chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << “Waited " << elapsed.count() << " ms\n”;
return 0;
}
运行程序输出:
Hello waiter
Waited 2000.07 ms