【问题标题】:std::this_thread::sleep_for sleeps shorter than expected in VS2015std::this_thread::sleep_for 在 VS2015 中的睡眠时间比预期的短
【发布时间】:2016-06-14 23:27:33
【问题描述】:

让我们有以下代码,它只是测量std::this_thread::sleep_for 的持续时间,调用时间为 20 毫秒:

#include <iostream>
#include <chrono>
#include <thread>

using namespace std;
using namespace std::chrono;

int main()
{
    for (int i = 0; i < 20; i++)
    {
        auto start = steady_clock::now();
        this_thread::sleep_for(milliseconds(20));
        auto end = steady_clock::now();
        duration<double, milli> elapsed = end - start;
        cout << "Waited " << elapsed.count() << " ms\n";
    }
}

当使用工具集 v120(VS2013 的)编译运行时,我得到了预期的结果,即:

Waited 20.0026 ms
Waited 20.0025 ms
Waited 20.0025 ms
Waited 20.0026 ms
Waited 20.0025 ms
Waited 20.0025 ms
Waited 20.0026 ms
Waited 20.0025 ms
Waited 20.0025 ms
Waited 20.0026 ms

但是当使用 VS2015 的工具集 v140 运行时,结果有些令人惊讶,并且不尊重 msdncppreference.com sleep_for 描述的承诺(sleep_for 阻止当前线程的执行 至少指定的sleep_duration)。它们如下:

Waited 19.7793 ms
Waited 19.9415 ms
Waited 19.6056 ms
Waited 19.9687 ms
Waited 19.608 ms
Waited 19.589 ms
Waited 20.5435 ms
Waited 19.5669 ms
Waited 19.6802 ms
Waited 19.5381 ms

这怎么可能,我怎样才能让 VS2015 的 sleep_for 至少像预期的那样休眠?

问候,大卫

编辑:

根据要求,这些是我的设置和操作系统详细信息:
操作系统

  • Windows 7 专业版 64 位

  • Visual Studios:2010 Ultimate、2013 Community、2015 Professional with Update 1

编译器设置

  • Win32 控制台应用程序的默认设置,

  • 任何调试和发布配置,

  • 任何 x86 和 x64 目标平台架构

【问题讨论】:

  • 我一般在循环中使用sleep_until(),以防早起。我认为早醒不应该发生,但在 GCC Linux 上,至少,只要进程收到信号(显然不是你的问题),早醒似乎就会发生。
  • 我在本地看不到相同的结果,例如在rextester.com/l/cpp_online_compiler_visual 上(它也在使用 VS2015)。考虑添加有关您的确切编译器设置、目标架构、主机操作系统、机器规格等的更多信息。
  • @Yirkha:我在描述中添加了更多关于我的条件的详细信息。至于你的结果 - 它看起来像是在我的系统中寻找微小的差异。

标签: c++ c++11 visual-studio-2013 visual-studio-2015


【解决方案1】:

VS2015 中的sleep_for() 方法实现已经包含一个围绕Sleep() 系统调用的循环,因此任何虚假唤醒都不会影响它 - 请参阅VC\crt\src\stl\cthread.c 中的_Thrd_sleep()


问题的原因很可能是sleep_for() 和它在内部调用的sleep_until() 使用chrono::system_clock 计算等待时间,但您使用chrono::steady_clock 测量周期。

两个计时器可能具有相同的精度,但不一定具有相同的精度。然后可能会发生system_clock有点滞后,而steady_clock已经提前了几微秒,使用system_clock计算的等待时间实际上比请求的要短。


在这种情况下,steady_clock 是使用QueryPerformanceCounter() 实现的(请参阅VC\include\chrono,搜索struct steady_clock),因此它将非常准确和精确,因为这是用于精确时间的首选 Windows API测量。

system_clock 是使用GetSystemTimePreciseAsFileTime() 实现的(请参阅VC\include\chrono,搜索struct system_clock),它还承诺“尽可能高的精度(。唉,正如 MSDN 页面所说,此 API 仅从 Windows 8 开始受支持,而您在 Windows 7 机器上只能使用较旧的GetSystemTimeAsFileTime(),精度仅为毫秒。这很可能是您的测量错误的结果。


根据您的具体用例,您当然可以用不同的方式处理这个问题。我会考虑忽略这个小错误,因为挂起线程并等待调度程序唤醒它无论如何都不会很准确。

【讨论】:

  • 看起来确实是因为sleep_for使用的时钟和我的测量方法不同。检查我是否已将测量时钟临时更改为system_clock,结果与预期的一样。然而,这是非常可疑的,因为您没有在本地复制此效果,这让我认为您的 sleep_for 使用 steady_clock。如果是这样,如果它取决于操作系统条件,有没有办法让sleep_for 使用steady_clock
  • 这是在 CRT 内部实现的,甚至没有通过 chrono 接口实现,因此您必须重新构建它 - 所以不。 Windows 升级 >=8 可以解决所有问题,或者您可以在受影响的平台上添加少量持续时间(以使“等待 >=X”要求始终为真)。
【解决方案2】:

虽然标准规定实现应该steady_clock 用于*_for 计时功能,但这不是必需的。如果使用不稳定的时钟,则时钟的调整会导致睡眠时间缩短。在这种情况下,计时功能可能无法提供标准所指出的有用功能

但是,您的结果显示持续的空头下跌,我认为这可能表明行为不符合标准。

您可以通过使用自己选择的时钟自己测量时间并循环休眠直到目标时间过去来解决这种行为。

【讨论】:

    猜你喜欢
    • 2020-10-19
    • 1970-01-01
    • 2020-10-15
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 2020-10-07
    相关资源
    最近更新 更多