gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 22:11:12 34 4
gpt4 key购买 nike

众所周知,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
    #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++(Debian 4.9.2-10)4.9.2上的结果: clock()= 0.00秒
    sleep(3) took: 

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

    C++ MSVS 2013 v120(Windows 7x64)上的结果:
    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
    #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++(Debian 4.9.2-10)4.9.2上的结果: clock()= 1.35秒
    for-loop took: 

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

    C++ MSVS 2013 v120(Windows 7x64)上的结果:
    for-loop took:

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

    恢复:
  • 当线程休眠时,g++ 4.9.2上的clock()不会像其他函数那样测量时间。
  • 当我们使用OpenMP或<thread>(link)使用多线程时,则g++ 4.9.2上的clock()会测量所有线程的CPU周期。

  • 同样在Windows MSVS 2013上,这两种情况下 clock()都需要实时测量,但这不能保证 clock()在其他平台上也可以实现相同的测量(在Linux上,对于 sleep ,g++为0,对于多线程,x-fold)。

    基于此,如果 std::chrono::high_resolution_clock::now();在Windows MSVS 2013和g++ 4.9.2上都同时测量了两种情况下所需的实时性,是否保证了它将在所有其他平台上测量实际的高分辨率时间,并且是否保证了标准的C++ 11/14吗

    最佳答案

    简短的答案:从C++ 14标准开始,high_resolution_clock不会明确提供您要寻找的保证。

    目前,steady_clocksystem_clock提供了更好,更明确的保证。但是,大多数实现可能会确保HRC在其线程处于休眠状态时继续前进。尽管如此,最好还是自己进行类型别名。请参阅下面的“编辑”部分以及评论中的讨论。

    长答案:

    draft standard实际上确实隐式地承认(在注释30.2.4“定时规范”,注释5中),时钟对象是,而不是在关联线程处于休眠状态时需要前进的。就上下文而言,本节说明标准库计时器对象如何工作。计时器的行为基于用于对其进行设置的时钟的行为。

    [ Note: If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these timeouts might not provide useful functionality. — end note ]



    请注意,在这种情况下,“超时可能无法提供有用的功能”意味着,如果您使用计时器通过不同步的(非实时)时钟对特定的时钟时间 sleep_until编码,则您的线程将不会唤醒。因此,上面的说明有些轻描淡写。

    而且,实际上,在Clock规范(20.13.3)中没有任何内容需要与稳定时钟进行同步。

    但是,该标准似乎隐含地宽恕了20.13.7.3中定义中 high_resolution_clock的两个可能的别名:

    high_resolution_clock may be a synonym for system_clock or steady_clock.


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

    但是, system_clock(20.13.7.1) 仍然是“实时”时钟:

    Objects of class system_clock represent wall clock time from the system-wide realtime clock.



    因此,当线程进入休眠状态时, system_clock 不会继续停止前进。
    这证实了Nicol Bolas的观点,即即使该时钟的行为符合您的预期,即 is_steadyhigh_resolution_clock可能为false(即,不管其相关线程的状态如何,它都会前进)。

    基于此,期望大多数主流实现对 high_resolution_clock使用某种实时(即同步)时钟似乎是合理的。毕竟,实现被设计为有用的,并且如果时钟不是实时的,则时钟通常没有那么有用,尤其是按照上面“有用功能”的注释,如果它与计时器一起使用,则尤其如此。

    但是,由于不能保证,因此应检查要使用的每个实现的行为和/或文档。

    编辑:我已就此问题启动了 discussion on the ISO C++ Standards group,表明这是标准中的错误。霍华德·海因南特(Howard Hinnant)的第一个答复值得一提:他将其纳入标准之中。

    I would not be opposed to deprecating high_resolution_clock, with the intent to remove it after a suitable period of deprecation. The reality is that it is always a typedef to either steady_clock or system_clock, and the programmer is better off choosing one of those two and know what he’s getting, than choose high_resolution_clock and get some other clock by a roll of the dice.



    ...根据Hinnant的说法,道德是 请勿使用high_resolution_clock

    编辑2:

    根据Hinnant的 high_resolution_clock的问题不是那么多,您很可能会遇到HRC的问题(尽管根据上面的参数,即使使用兼容的编译器,这也是可能的),但是由于您通常实际上并没有获得比其他两个时钟之一更低的分辨率(尽管您需要在类型别名或typedef中手动比较它们的分辨率,以获得“最大分辨率”的非 sleep 时钟),没有具体的好处。因此,您需要权衡使线程在符合标准的实现中永久 sleep 的风险,名称 high_resolution_clock的语义优势以及避免仅制作自己的typedef或类型别名的简单性/简洁性优势。

    这是各种方法的一些实际代码:
  • 使用static_assert来检查high_resolution_clock是否实际上是真实时钟的别名。这可能永远不会触发,这意味着您将自动获得最高分辨率的“实时”时钟,而不会弄乱您自己的typedef:
     static_assert(
    std::is_same<high_resolution_clock, steady_clock>::value
    || std::is_same<high_resolution_clock, system_clock>::value,
    "high_resolution_clock IS NOT aliased to one of the other standard clocks!");
  • 如果high_resolution_clock::is_steady为true,则使用HRC;否则为false。否则,建议使用system_clocksteady_clock之间的高分辨率时钟。 注意,如果high_resolution_clock::is_steady为false,则可能仅意味着HRC别名为system_clock,在这种情况下,您最终将得到一个新的类型别名,该别名实际上与high_resolution_clock相同。但是,创建自己的类型别名使这一点很明确,并保证即使是恶意但合规的实现也不会出现上述问题。
    using maxres_sys_or_steady =
    std::conditional<
    system_clock::period::den <= steady_clock::period::den,
    system_clock, steady_clock
    >::type;
    using maxres_nonsleeping_clock =
    std::conditional<
    high_resolution_clock::is_steady,
    high_resolution_clock, maxres_sys_or_steady
    >::type;
  • 关于c++ - 标准C++ 11是否保证high_resolution_clock测量实时(非CPU周期)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38252022/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com