首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >steady_clock与system_clock的区别?

steady_clock与system_clock的区别?
EN

Stack Overflow用户
提问于 2015-07-22 01:03:10
回答 5查看 40.6K关注 0票数 52

我试图通过查看数据的时间戳来查看我的数据是否有120秒的历史,因此我有以下代码:

代码语言:javascript
复制
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,所以现在和数据持有者时间戳的区别应该是负的,对吗?为什么它会像下面的日志中所示的那样是正的呢?

代码语言:javascript
复制
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在外行方面的区别是什么?我正在Ubuntu14.04框上运行这段代码。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-07-22 04:01:08

以相反顺序回答问题:

steady_clocksystem_clock在外行方面的区别是什么?

如果你手里拿着一个system_clock,你就叫它手表,它会告诉你现在是什么时候。

如果你手里拿着一个steady_clock,你会称它为秒表,它会告诉你某人跑一圈有多快,但它不会告诉你现在是什么时候。

如果你必须的话,你可以用你的手表给某人计时一圈。但是,如果你的手表(像我的)定期与另一台机器(如Boulder中的原子钟)交谈,以修正自己的时间,它可能会在计时上犯一些小错误。秒表不会犯这个错误,但它也不能告诉你正确的当前时间是什么。

我上面的代码看上去对吗?

不是的。即使它给了你合理的答案,我也不会说它是对的。不要难过,这是很多人在使用<chrono>库时犯的一个初学者错误。

对于<chrono>库,我遵循一个简单的规则。这个规则实际上是不完全正确的(因此它是一个指南)。但是,它已经足够接近,足以成为几乎总是遵循的指导方针:

不要使用count()

还有一个推论:

不要使用time_since_epoch()

<chrono>库是围绕一个类型安全系统设计的,目的是保护您免受单元转换错误的影响。如果意外尝试不安全的转换,则会在编译时捕获错误(而不是运行时错误)。

成员函数count()time_since_epoch()是这种类型安全系统的“逃生舱口”.只在紧急情况下使用。当委员会忽略给您完成<chrono>类型的工作所需的所有工具(例如I/O),或者需要通过整数与其他定时API接口时,就会出现这种紧急情况。

检查您的代码和其他代码,以便使用count()time_since_epoch(),并仔细检查这些函数的每一种用法:是否可以重写代码以消除它们的使用?

检查代码的第一行:

代码语言:javascript
复制
uint64_t now = duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();

nowtime_point (来自steady_clock)。It单元是milliseconds,但此时我不确定这些单元是重要的。重要的是,now是从steady_clock检索的time_point

代码语言:javascript
复制
auto now = steady_clock::now();

你的第二行更复杂:

代码语言:javascript
复制
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>,要么用time_point<system_clock, milliseconds>包装getTimestamp()的返回

代码语言:javascript
复制
auto dh_ts = system_clock::time_point{milliseconds{data_holder->getTimestamp()}};

现在,您的第二行是:

代码语言:javascript
复制
bool is_old = (120 * 1000 < (now - dh_ts));

另一个很好的指导方针是:

如果您在<chrono>代码中看到了转换因素,那么您就错了。<chrono>是为你做转换而生的。

代码语言:javascript
复制
bool is_old = (minutes{2} < (now - dh_ts));

接下来的步骤是风格化的,但是现在您的代码足够简单,可以去掉多余的括号,如果这对您有吸引力的话:

代码语言:javascript
复制
bool is_old = minutes{2} < now - dh_ts;

如果您能够修改getTimestamp()以返回一个类型安全值,那么这段代码也可以如下所示:

代码语言:javascript
复制
bool is_old = minutes{2} < now - data_holder->getTimestamp();

唉,不管怎样,这还是不能编译的!错误消息应该声明在nowdh_ts之间没有有效的dh_ts

这是类型安全系统进来,以避免您运行时错误!

问题是,来自system_clocksystem_clocks不能从steady_clocktime_points中减去(因为这两者有不同的时代)。所以你必须切换到:

代码语言:javascript
复制
auto now = system_clock::now();

把这一切结合在一起:

代码语言:javascript
复制
#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中,最后一行可以变得更简洁一些:

代码语言:javascript
复制
    bool is_old = 2min < now - data_holder->getTimestamp();

总结如下:

  • 拒绝使用count() (I/O除外)。
  • 拒绝使用time_since_epoch() (I/O除外)。
  • 拒绝使用换算系数(如1000)。
  • 和它争论,直到它编译为止。

如果您在上述四点上取得成功,您很可能不会遇到任何运行时错误(但您将得到编译时错误的公平份额)。

票数 137
EN

Stack Overflow用户

发布于 2019-03-19 05:27:38

  1. steady_clock使用系统启动时间作为它的时代,system_clock使用1970-1-100:00作为它的时代,所以没有办法在它们之间做任何数学运算,这是没有意义的。
  2. 在两个无符号整数之间做任何减法之前,请确保分钟大于减号。
票数 4
EN

Stack Overflow用户

发布于 2015-07-22 01:13:05

第一件事

您看到正值的原因是由于无符号整数环绕。试试这个,看看:

代码语言:javascript
复制
std::cout << static_cast <uint64_t> (-1) << std::endl;

getTimestamp()返回的值是预期的吗?如果不是的话,如果没有看到getTimestamp()的实现,就很难看出出了什么问题。看起来时间戳不是用同一个时钟来测量的。

稳定相对于系统时间

稳定的时钟是测量时间间隔的最佳方法。引用cppreference.com

类std::chrono::steady_clock表示一个单调的时钟。这个时钟的时间点不能随着物理时间的推移而减少。此时钟与挂钟时间无关,最适合测量间隔时间。

与system_clock不同,后者不是单调的(也就是说,如果用户更改主机上的时间,时间就会减少)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31552193

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档