睡眠函数Sleep()存在不准确性吗?

3

我正在开发一个计时系统,将实现一个定时器类。

#include <windows.h>
#include <stdio.h>
#include <time.h>

int main()
{
    clock_t t1, t2;
    t1 = clock();
    Sleep(10);
    t2 = clock();
    printf("%i\n", (int)(t2 - t1));
    return 0;
}

这个程序应该打印“10”,但它打印了“15”或“16”。我需要更精确的结果,误差应小于1毫秒!有什么建议吗?(也许可以使用select()的超时机制?)
注意:我在Windows 7 Ultimate x86上运行了此程序。程序使用MinGW (C/C++) x86编译。 现在我想知道的是>>
3个回答

4

Sleep() 函数是根据操作系统的时钟中断速率精确计时的。在 Windows 上,默认情况下每秒会有 64 个时钟中断。也就是每 15.625 毫秒会有一次时钟中断,就像你发现的那样。

你可以增加这个速率,调用 timeBeginPeriod(10)。完成后使用 timeEndPeriod(10)。你仍然受到正常线程调度延迟的影响,因此不能保证在 10 毫秒后您的线程将恢复运行,当机器负载过重时则更不���能。使用 SetThreadPriority() 来提高优先级,增加线程恢复运行的几率。


1
甚至可以使用timeBeginPeriod(1)等函数。但更好的方法是使用通过调用timeGetDevCaps填充的TIMECAPS结构体中的wPeriodMin参数。 注意:结果的时间间隔取决于底层硬件。 - Arno
只询问您需要的内容,使用1是浪费的。最小周期并不太重要,因为它已经自动调整了,如果超过您的需求,您也无法做任何事情。最后一个不支持这个的机器早在15年前就已经消失了。 - Hans Passant
这是否过多?调用Sleep(10)可能不会总是在相位中,在中断时刻发生。当使用timeBeginPeriod(10)时,提前5毫秒调用Sleep(10)将导致总共睡眠15毫秒。 - Arno
是的,没错。不过,代码已经在时钟中断处开始运行了,所以存在意外相位问题。 - Hans Passant
好的,这些方法可能会有一些循环结构,但是这里给出的代码是异步的。...没关系。 - Arno

2
你的问题是“时钟”每秒只跳动64次(我见过的系统最高可达2000,但没有更高)。如果你正在创建一个计时器类,你可能希望拥有比2000更高的分辨率。使用QueryPerformanceCounter获取更高的分辨率。参见QueryPerformanceCounter和溢出以获取示例。
请注意,如果你想要睡眠非常短的时间间隔,你将不得不在紧密的循环中调用QueryPerformanceCounter

@PilawyerDev:不,这只适用于Windows操作系统。 - Gabe
谢谢!没问题。我认为我可以使用信号处理和(阻塞/互斥)队列来实现我的计时器类和计时线程。 - PilawyerDev
1
@PilawyerDev:为什么要跨平台?你明确要求了一个Windows解决方案。 - Arno

1

Sleep()在您期望的方式上不是准确的。

它会导致线程至少休眠指定的时间长度,但不能保证操作系统会恰好在指定的时间将控制返回给您的线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接