为什么睡眠(500)花费超过500毫秒?

时间:2015-11-12 12:31:47

标签: c++ winapi sleep

我在代码中使用Sleep(500)并使用getTickCount()来测试时间。我发现它的成本约为515ms,超过500.有人知道为什么会这样吗?

7 个答案:

答案 0 :(得分:63)

因为Win32 API的Sleep不是高精度睡眠,并且具有最大粒度。

获得精确睡眠的最佳方法是睡眠少一点(约50毫秒)并进行忙碌等待。要找到您需要忙碌的准确时间,请使用timeGetDevCaps获取系统时钟的分辨率,然后乘以1.5或2以保证安全。

答案 1 :(得分:30)

sleep(500)保证的睡眠时间至少 500毫秒。

但它可能会睡得更久:没有定义上限。

在您的情况下,调用getTickCount()时还会有额外的开销。

您的非标准Sleep功能可能表现得与众不同;但我怀疑是否保证了准确性。要做到这一点,你需要特殊的硬件。

答案 2 :(得分:18)

正如您可以在the documentation中阅读,WinAPI函数GetTickCount()

  

仅限于系统计时器的分辨率,通常在10毫秒到16毫秒的范围内。

要获得更准确的时间测量,请使用函数GetSystemDatePreciseAsFileTime

此外,您不能依赖Sleep(500)睡眠完全 500毫秒。它会暂停的线程至少 500毫秒。一旦有可用的时隙,操作系统将继续该线程。当操作系统上运行许多其他任务时,可能会有延迟。

答案 3 :(得分:13)

一般情况下,睡眠意味着你的线程进入等待状态,并且在500ms之后,它将处于" runnable"州。然后OS调度程序根据当时可运行进程的优先级和数量选择运行某些。因此,如果你有高精度睡眠和高精度时钟,那么它仍然是一个至少500毫秒的睡眠,而不是500毫秒。

答案 4 :(得分:12)

与其他答案一样,Sleep()的准确性有限。实际上, no 实现类似Sleep()的功能可以完全准确,原因如下:

  • 实际调用Sleep()需要一些时间。虽然旨在实现最大准确度的实现可以尝试测量并补偿这种开销,但很少有人费心。 (并且,无论如何,由于许多原因(包括CPU和内存使用),开销可能会有所不同。)

  • 即使Sleep()使用的基础计时器在发射所需的时间,也无法保证您的进程在唤醒后会立即重新安排。您的进程在睡眠时可能已被换出,或者其他进程可能会占用CPU。

  • 操作系统可能无法在请求的时间唤醒您的进程,例如因为计算机处于挂起模式。在这种情况下,您的500毫秒Sleep()电话很可能最终需要几个小时或几天。

此外,即使Sleep()非常准确,您想要在睡眠后运行的代码也不可避免地会消耗一些额外的时间。 因此,为了定期执行某些操作(例如重绘屏幕或更新游戏逻辑),标准解决方案是使用补偿 Sleep()循环。也就是说,您维护一个定期递增的时间计数器,指示下一个动作何时发生,并将此目标时间与当前系统时间进行比较,以动态调整您的睡眠时间。

需要特别注意处理意外的大时间跳跃,例如:如果计算机暂时被怀疑或计数器计数器缠绕在一起,以及处理操作的时间比下一次操作之前的时间更长,导致循环滞后。

这是一个应该处理这两个问题的快速示例实现(伪代码):

int interval = 500, giveUpThreshold = 10*interval;
int nextTarget = GetTickCount();

bool active = doAction();
while (active) {
    nextTarget += interval;
    int delta = nextTarget - GetTickCount();
    if (delta > giveUpThreshold || delta < -giveUpThreshold) {
        // either we're hopelessly behind schedule, or something
        // weird happened; either way, give up and reset the target
        nextTarget = GetTickCount();
    } else if (delta > 0) {
        Sleep(delta);
    }
    active = doAction();
}

这将确保doAction()平均每<{1}}毫秒调用一次,至少只要它不会持续消耗更多的时间,并且只要没有大的时间跳跃发生。连续调用之间的确切时间可能会有所不同,但任何此类变化都将在下一次调整时得到补偿。

答案 5 :(得分:2)

默认计时器分辨率很低,您可以根据需要增加时间分辨率。 MSDN

PCFunc = Func.PCFunc ()

答案 6 :(得分:1)

代码可能需要像#34; sleep&#34;:

这样的函数有两个一般原因
  1. 它有一些任务可以在将来至少有一段距离的任何时间执行。

  2. 它有一些任务应尽可能在将来的某个时刻尽可能地进行。

  3. 在一个好的系统中,应该有单独的方式发出这类请求; Windows使第一个比第二个更容易。

    假设系统中有一个CPU和三个线程,这些线程都很有用 工作到午夜前一秒钟,其中一个主题说它不会有 任何有用的事情至少一秒钟。那时,系统会 将执行权交给剩下的两个线程。如果,在午夜前1ms, 其中一个线程决定它至少没有任何有用的东西 第二,系统将控制切换到最后剩余的线程。

    当午夜滚动时,原始的第一个线程将可用 运行,但由于当前正在执行的线程将只有CPU 那时的毫秒,原始的第一个没有特别的原因 线程应该被认为更多&#34;值得&#34; CPU时间比其他线程 刚得到控制权。由于切换线程不是免费的,因此操作系统可能非常自由 确定当前拥有CPU的线程应该保留它直到 它会阻塞某些东西或耗尽整个时间片。

    如果有一个版本的&#34; sleep&#34;那可能会很好。哪个更容易使用 比多媒体计时器,但会要求系统给线程a 当它有资格再次运行或更好时,临时优先级提升 睡眠的变化&#34;睡眠&#34;这将指定最短时间和优先级 - 升压&#34;时间,适用于需要在特定时间窗口内执行的任务。但是,我不知道任何可以轻松地以这种方式工作的系统。