chrono_Time_point (三)

chrono_time_point (三)

模板参数

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提供的操作如下:

img

timepoint的溢出

  • 虽然timepoint的接口用了ratio,这确保了duration单元的溢出会导致编译器报错,但是duration的溢出还是可能会发生
  • 见下面的例子:

img

img

  • 这也说明了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++标准的说法,也并不保证如此

img

演示案例(timepoint和日历时间的转换)

img

img

img

以计时器停滞线程

  • 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
posted @ 2023-02-07 16:26  Ding-yixia  阅读(82)  评论(0)    收藏  举报