使用 std::chrono 的时间戳 - 如何根据相对时间 'filter' 数据?

Time-stamping using std::chrono - How to 'filter' data based on relative time?

我想对我生成的数据流进行时间标记,为此我想使用 std::chrono::steady_clock.

这些时间戳与数据一起存储(作为 uint64 值的数组?),我稍后需要再次处理这些时间戳。

现在,到目前为止我还没有使用过 std::chrono 库,所以我确实需要一些关于这个库的语法和最佳实践的帮助。

我可以使用以下方法获取和存储值:

uint64_t timestamp = std::chrono::steady_clock::now().time_since_epoch().count();

但我怎样才能做到最好:

以上代码片段将不胜感激。

我想结合以上三者来执行以下操作:有一个(增加的)时间戳值数组(如 uint64),我想截断它,以便所有数据 'older' 比最后一个-时间戳减去 X 秒被丢弃。

像往常一样看起来不错的地方是参考手册:

https://en.cppreference.com/w/cpp/chrono

在这种情况下,您正在寻找:

https://en.cppreference.com/w/cpp/chrono/clock_time_conversion

因为您确实使用了以“纪元”1/1/70 为原点、以毫秒为单位的时钟。 然后只需对持续时间使用算术来完成你想要的截止操作:

https://en.cppreference.com/w/cpp/chrono/duration

每个链接页面的底部都有代码示例。

让我们看看您可能会在 chrono 的 cppreference 文档中使用的功能。

首先,您需要决定要使用哪个时钟。有您建议的 steady_clockhigh_resolution_clocksystem_clock

high_resolution_clock 依赖于实现,所以除非我们真的需要它,否则让我们把它收起来。 steady_clock 保证是单调的,但不能保证您获得的值的含义。它非常适合对事件进行排序或测量它们的间隔,但您无法从中获取时间点。

另一方面,system_clock有一个含义,它是UNIX纪元,所以你可以从中得到一个时间值,但不保证是单调的。

要获得 steady_clock 的周期(一个报价的持续时间),您有 period 成员:

auto period = std::chrono::steady_clock::period();
std::cout << "Clock period " << period.num << " / " << period.den << " seconds" << std::endl;
std::cout << "Clock period " << static_cast<double>(period.num) / period.den << " seconds" << std::endl;

假设您想使用 steady_clock 值过滤最近几秒内发生的事件,您首先需要计算所需时间段内的滴答数,然后从 now 中减去它.大致如下:

std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t t_c = std::chrono::system_clock::to_time_t(now - std::chrono::seconds(10));

并使用t_c作为分界点。

但是,不要依赖 std::chrono::steady_clock::now().time_since_epoch().count(); 来获得有意义的东西 - 只是一个数字。 steady_clock 的纪元通常是引导时间。如果你需要一个时间,你应该使用system_clock(记住这不是单调的)。

C++20a 引入了更多时钟,可转换为时间。

由于今天我花了太长时间才从各种来源弄清楚,所以我将post 此处作为我的解决方案self-answer。 (如果有不正确的地方或可以做得更好,我将不胜感激。)

获取时钟的周期(以秒为单位)和 ticks-per-second 值

    using namespace std::chrono;
    auto period = system_clock::period();
    double period_s = (double) period.num / period.den; 
    uint64 tps = period.den / period.num;

获取时钟的时间点(现在)作为 time-stamping 数据流的 uint64 值

    using namespace std::chrono;
    system_clock::time_point tp_now = system_clock::now();
    uint64 nowAsTicks = tp_now.time_since_epoch().count();

根据存储的 uint64 值获取时钟的时间点

    using namespace std::chrono;
    uint64 givenTicks = 12345;  // Whatever the value was
    system_clock::time_point tp_recreated = system_clock::time_point{} + system_clock::duration(givenTicks);
    uint64 recreatedTicks = tp_now.time_since_epoch().count();
    Assert( givenTicks == recreatedTicks );  // has to be true now

最后一个(uint64 到时间点)最让我困扰。需要的 key-insights 是:

  • (在 Win10 上)system_clock 使用 100 纳秒的 time-resolution。因此不能直接将 std::chrono::nanoseconds 添加到其本机时间点。 (std::chrono:system_clock_time_point)

  • 但是,由于滴答是 100 纳秒,因此也不能使用下一个更高的持续时间单位(微秒),因为它不能表示为整数值。

  • 可以使用 显式 转换为微秒,但这会失去滴答声的 0.1us 分辨率。

  • 正确的做法是使用system_clock自身的duration,直接用存储的tick值初始化

在我的搜索中,我发现以下资源最有帮助: