首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >标准C++11是否保证high_resolution_clock测量实时(非CPU周期)?

标准C++11是否保证high_resolution_clock测量实时(非CPU周期)?
EN

Stack Overflow用户
提问于 2016-07-07 17:45:32
回答 2查看 7.2K关注 0票数 20

众所周知,clock()显示的值可能小于或大于实时值--这两种情况都显示在下面的示例1和2中。

对于C++11中时间的高精度测量,我们可以使用:

  • std::chrono::high_resolution_clock::now(); -保证高精度
  • std::chrono::steady_clock::now(); -保证测量的实时性
  • clock(); -保证高精度,但测量CPU周期而不是时间。
  • time(&t_start); -不是高精度的,而是实时测量。

1-,例如:http://ideone.com/SudWTM

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>

int main(void) {

    std::cout << "sleep(3) took: \n\n";

    clock_t c_start, c_end;
    time_t t_start, t_end;
    std::chrono::high_resolution_clock::time_point h_start, h_end;
    std::chrono::steady_clock::time_point steady_start, steady_end;

    time(&t_start);  // less precise than clock() but always get the real actual time
    c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds 
    h_start = std::chrono::high_resolution_clock::now();
    steady_start = std::chrono::steady_clock::now(); 

    std::this_thread::sleep_for(std::chrono::seconds(3));

    steady_end = std::chrono::steady_clock::now();
    h_end = std::chrono::high_resolution_clock::now();
    c_end = clock();
    time(&t_end);

    std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
    std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";

    printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
    printf("time() = %.2lf seconds \n", difftime(t_end, t_start));

    return 0;
}

g++上的结果(Debian4.9.2-10) 4.9.2:clock() = 0.00秒

代码语言:javascript
复制
sleep(3) took: 

highres = 3.00098 s 
steady = 3.00098 s 
clock() = 0.00 seconds 
time() = 3.00 seconds 

C++ MSVS 2013 v120 (Windows7x64)的结果:

代码语言:javascript
复制
sleep(3) took:

highres = 3.00017 s
steady = 3.00017 s
clock() = 3.00 seconds
time() = 3.00 seconds

2-第二个示例OpenMP或<thread>http://coliru.stacked-crooked.com/a/2922c85385d197e1

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>
#include <vector>

int main(void) {

    std::cout << "for-loop took: \n\n";

    clock_t c_start, c_end;
    time_t t_start, t_end;
    std::chrono::high_resolution_clock::time_point h_start, h_end;
    std::chrono::steady_clock::time_point steady_start, steady_end;

    time(&t_start);  // less precise than clock() but always get the real actual time
    c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds 
    h_start = std::chrono::high_resolution_clock::now();
    steady_start = std::chrono::steady_clock::now();

    #pragma omp parallel num_threads(10)
    {
        for (volatile int i = 0; i < 200000000; ++i);
    }

    steady_end = std::chrono::steady_clock::now();
    h_end = std::chrono::high_resolution_clock::now();
    c_end = clock();
    time(&t_end);

    std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
    std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";

    printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
    printf("time() = %.2lf seconds \n", difftime(t_end, t_start));

    int b = getchar();

    return 0;
}

g++上的结果(Debian4.9.2-10) 4.9.2:clock() =1.35秒

代码语言:javascript
复制
for-loop took: 

highres = 0.213906 s 
steady = 0.213905 s 
clock() = 1.35 seconds 
time() = 0.00 seconds 

C++ MSVS 2013 v120 (Windows7x64)的结果:

代码语言:javascript
复制
for-loop took:

highres = 1.49109 s
steady = 1.49109 s
clock() = 1.49 seconds
time() = 2.00 seconds

简历:

  1. 当线程休眠时,clock()在g++ 4.9.2上并不测量时间,与其他函数不同。
  2. 当我们使用OpenMP或<thread> (链接)进行多线程处理时,g++ 4.9.2上的clock()会测量所有线程的CPU周期。

同样,在Windows 2013中,clock()测量在这两种情况下都需要实时,但这并不能保证clock()在其他平台上的测量相同(在linux g++上,睡眠为0,多线程为x折叠)。

基于此,如果在Windows 2013和g++ 4.9.2两种情况下都需要实时测量,这是否保证它将在所有其他平台上测量真正的高分辨率时间,以及它是否保证标准C++11/14?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-07 18:55:16

简短的回答:根据C++14标准,high_resolution_clock没有明确提供您想要的保证。

目前,steady_clocksystem_clock提供了更好和更明确的保证。然而,大多数实现可能会确保HRC在线程处于休眠状态时继续前进。尽管如此,它可能是更好的做你自己的类型混叠。请参阅下面的“编辑”部分和评论中的讨论。

较长的答覆:

实际上,标准草案确实隐式地承认(注30.2.4“定时规范”,注5)时钟对象是而不是,因为它们的关联线程处于休眠状态。对于上下文,本节解释标准库计时器对象是如何工作的;定时器的行为是基于用来设置它的时钟的行为。

注意:如果时钟与稳定的时钟(例如CPU时钟)不同步,这些超时可能无法提供有用的功能。-尾注

请注意,在这种情况下,“超时可能无法提供有用的功能”意味着,如果您使用一个计时器使用一个不同步(非实时)时钟sleep_until特定时钟时间,您的线程将不会唤醒。所以上面的注释有点轻描淡写。

而且,实际上,时钟规范(20.13.3)中没有任何实际需要与稳定时钟同步的东西。

然而,在20.13.7.3中的定义中,该标准似乎含蓄地容忍了high_resolution_clock的两个潜在别名:

high_resolution_clock可以是system_clocksteady_clock的同义词。

当然,steady_clock是稳定的。system_clock而不是,因为程序运行时系统时间可能会改变(例如,NTP更新的结果)。

然而,system_clock (20.13.7.1) 仍然是一个“实时”时钟:

system_clock对象表示来自系统范围的实时时钟的挂钟时间.

因此,当线程休眠时,system_clock 不会停止前进。这证实了Nicol的观点,即is_steady对于high_resolution_clock来说可能是错误的,即使时钟的行为与您预期的一样(也就是说,无论其关联线程的状态如何,它都会前进)。

基于此,期望大多数主流实现为high_resolution_clock使用某种类型的实时(即同步)时钟似乎是合理的。毕竟,实现被设计成有用的,如果时钟不是实时的,那么它通常就不太有用了,特别是按照上面关于“有用功能”的说明,它与定时器一起使用时更是如此。

但是,由于不能保证这一点,所以您应该检查要使用的每个实现的行为和/或文档。

编辑:--我已经在这个问题上启动了一个国际标准化组织C++标准组的探讨,这表明这是标准中的一个bug。霍华德·辛南特( Howard Hinnant )提出的第一个答复值得引用:

我不反对反对high_resolution_clock,目的是在一段适当的反对期之后删除它。实际情况是,它总是steady_clocksystem_clock的类型,程序员最好选择这两种中的一种,并知道自己得到了什么,而不是选择high_resolution_clock并按骰子获得其他时钟。

根据辛纳特的说法,high_resolution_clock**.**的寓意是不使用

编辑2:

根据Hinnant的说法,high_resolution_clock的问题不在于你很可能在HRC中遇到问题(尽管按照上面的论点,即使使用符合标准的编译器也是可能的),但是由于您通常没有获得比其他两个时钟中的一个更低的分辨率(尽管您需要手动比较它们的分辨率(别名或类型)以获得“最大分辨率”而不是睡眠时钟),所以没有任何具体的好处。因此,您需要权衡让线程永远睡在一致性实现上的风险,而不是名称high_resolution_clock的语义好处,以及避免只使用您自己的type或类型别名所带来的简单/简洁的好处。

以下是各种方法的实际代码:

  • 使用static_assert检查high_resolution_clock是否实际上是一个真正的时钟。这可能永远不会触发,这意味着您将自动获得最高分辨率的“实时”时钟,而不会干扰您自己的字体: static_assert( std::is_same::value the std::is_same::value,"high_resolution_clock不是其他标准时钟的别名!“);
  • 如果high_resolution_clock::is_steady为真,则使用HRC;否则更喜欢system_clocksteady_clock之间的高分辨率时钟。注意到,如果high_resolution_clock::is_steady是false,这可能只是意味着HRC被别名为system_clock,在这种情况下,最终您将得到一个新的类型--别名实际上与high_resolution_clock的类型相同。但是,创建自己的类型别名可以显式地说明这一点,并保证即使是符合恶意但符合条件的实现也不会出现上述问题。 使用maxres_sys_or_steady = std::conditional< system_clock::period::den <= steady_clock::period::den,system_clock,steady_clock >:type;使用maxres_nonsleeping_clock = std::conditional< high_resolution_clock::is_steady,high_resolution_clock,maxres_sys_or_steady >:type;
票数 23
EN

Stack Overflow用户

发布于 2016-07-07 18:14:15

标准没有从它的时钟中指定这种行为。不完全同意。

时钟具有is_steady静态属性,可以对其进行检查。任何is_steady返回true的时钟都不能仅仅因为使线程处于休眠状态而停止运行。然而,由于各种原因,该值为假的时钟可能是不稳定的。它可能不是稳定的,因为如果系统时间发生变化,这是一个会改变的挂钟。或者是因为滴答之间的周期是一个平均值,而不是一个确切的数字。

所以is_steady并没有真正回答你的问题。

标准没有指定high_resolution_clock::is_steady,但它确实要求实现来回答这个问题。如果它是稳定的,那么你可以保证线程的睡眠不会停止时钟。但如果不稳定..。你根本得不到保证。

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

https://stackoverflow.com/questions/38252022

复制
相关文章

相似问题

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