c++ - 稳定时钟与系统时钟之间的区别?

标签 c++ c++11 timestamp

我试图通过查看数据的时间戳来查看我的数据是否为120秒旧数据,所以我有以下代码:

uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

在上面的代码中,data_holder->getTimestamp()是uint64_t,它以毫秒为单位返回时间戳。

现在,当我打印出now变量值时,我看到了这个10011360,并且当我打印出了data_holder->getTimestamp()1437520382241值时,现在和数据持有人时间戳的差应该为负吗?为什么它变得如下面的日志所示为正?
2015-07-21 16:13:02,530 WARN 0x7f35312d1700 data_check - now value: 10011360 , data holder timestamp: 1437520382241 , difference: 18446742636199180735

我上面的代码看起来正确吗?从上面的数据持有者时间戳来看,看起来好像不是120秒的旧数据,所以我觉得我的代码有问题吗?因为如果我将数据持有者时间戳转换为实际时间(使用纪元转换器),然后将其与日志时间进行比较(如上所示),则几乎是相同的。

我正在使用上面显示的steady_clock。我需要在这里使用system_clock吗?在外行方面,steady_clocksystem_clock有什么区别。我在Ubuntu 14.04机器上运行此代码。

最佳答案

以相反的顺序回答问题:

What is the difference between steady_clock vs system_clock in layman terms.



如果您手里拿着system_clock,您将其称为 watch ,它会告诉您现在几点了。

如果您手里拿着steady_clock,您将其称为秒表,它将告诉您某人跑完一圈的速度,但不会告诉您现在几点。

如果需要的话,您可以安排某人为您的 watch 跑一圈。但是,如果您的 watch (例如我的 watch )定期与另一台机器(例如Boulder CO中的原子钟)通话以将其校正为当前时间,则在计时该圈时可能会犯一些小错误。秒表不会犯该错误,但也无法告诉您正确的当前时间。

Does my above code look right?



不。即使它给了您合理的答案,我也不会说这是正确的。别担心,这是很多人使用<chrono>库犯的初学者错误。

我遵循<chrono>库有一个简单的规则。该规则实际上并不完全正确(因此这是一个准则)。但是,它几乎足以纠正成为几乎始终遵循的准则:

Don't use count().



还有一个推论:

Don't use time_since_epoch().


<chrono>库围绕类型安全的系统设计,旨在保护您免受单位转换错误的影响。如果您不小心尝试了不安全的转换,则该错误将在编译时捕获(与之相反,它是运行时错误)。

成员函数count()time_since_epoch()是此类型安全系统中的“转义线”,仅在紧急情况下使用。当(例如)委员会忽视为您提供完成<chrono>类型的工作所需的所有工具(例如I/O),或者例如需要通过整数与其他一些计时API交互时,就会出现此类紧急情况。

复查您的代码和其他代码是否使用count()time_since_epoch(),并仔细检查这些函数的每种用法:是否可以通过任何方式重写代码以消除其使用?

查看代码的第一行:
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
nowtime_point(来自steady_clock)。它的单位是milliseconds,但是目前我不认为这些单位很重要。重要的是now是从time_point检索的steady_clock:
auto now = steady_clock::now();

您的第二行更加复杂:
bool is_old = (120 * 1000 < (now - data_holder->getTimestamp()));

让我们从data_holder->getTimestamp()开始:如果可以修改getTimestamp(),则应该对其进行修改以返回time_point而不是uint64_t。为此,您将必须知道正确的单位(毫秒),,您必须知道正确的纪元。纪元是您以毫秒为单位的时间点。

在这种情况下1437520382241ms大约是45.6年。假设这是最近的时间戳,则45.6年前的时间与1970-01-01非常接近。事实证明,system_clock()的每个实现都使用1970-01-01作为其纪元(尽管每个实现从该纪元计算出不同的单位)。

因此,要么修改getTimestamp()以返回time_point<system_clock, milliseconds>,要么将getTimestamp()的返回结果包装在time_point<system_clock, milliseconds>中:
auto dh_ts = system_clock::time_point{milliseconds{data_holder->getTimestamp()}};

现在您的第二行是:
bool is_old = (120 * 1000 < (now - dh_ts));

另一个好的准则:

If you see conversion factors in your <chrono> code, you're doing it wrong. <chrono> lives for doing the conversions for you.


bool is_old = (minutes{2} < (now - dh_ts));

下一步是风格上的,但是现在代码很简单,可以消除多余的括号(如果这对您很有吸引力):
bool is_old = minutes{2} < now - dh_ts;

如果您能够修改getTimestamp()以返回类型安全的值,则该代码也可能类似于:
bool is_old = minutes{2} < now - data_holder->getTimestamp();

las,无论如何,这仍然无法编译!错误消息应大致说明operator-()now之间没有有效的dh_ts

This is the type-safety system coming in to save you from run time errors!



问题在于无法从time_pointsystem_clock减去time_pointsteady_clock(因为两者具有不同的时期)。因此,您必须切换到:
auto now = system_clock::now();

放在一起:
#include <chrono>
#include <cstdint>
#include <memory>

struct DataHolder
{
    std::chrono::system_clock::time_point
    getTimestamp()
    {
        using namespace std::chrono;
        return system_clock::time_point{milliseconds{1437520382241}};
    }
};

int
main()
{
    using namespace std;
    using namespace std::chrono;
    auto data_holder = std::unique_ptr<DataHolder>(new DataHolder);

    auto now = system_clock::now();
    bool is_old = minutes{2} < now - data_holder->getTimestamp();
}

在C++ 14中,可以使最后一行更加简洁:
    bool is_old = 2min < now - data_holder->getTimestamp();

综上所述:
  • 拒绝使用count()(I/O除外)。
  • 拒绝使用time_since_epoch()(I/O除外)。
  • 拒绝使用转换因子(例如1000)。
  • 对其进行争论,直到编译为止。

  • 如果您在以上四点中都成功了,则很可能不会遇到任何运行时错误(但是您会得到相当一部分编译时错误)。

    关于c++ - 稳定时钟与系统时钟之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31552193/

    相关文章:

    C++线程应用程序运行速度比非线程慢

    c++ - 如何使用一张 map 存储不同的功能

    双表MySQL时间戳(需要计算百分比)

    sql - 将日期添加到时间戳

    c++ - Mbed 吉他调音器代码问题?

    c++ - 获取圆角矩形周围的点

    c++ - 为什么在 C++ 中使用多线程时运行时间没有减半?

    c++ - unordered_set 示例编译器错误(哈希和等价函数错误可能)

    mysql - SQL 根据时间戳按年月排序

    c++ - CUDA 中的随机播放指令