Windows 8(.1)休眠时多等待1毫秒

4

在Windows 8.1 x64中,Sleep总是比所需的多睡眠1毫秒。例如,Sleep(1)持续大约2毫秒,Sleep(2)持续3毫秒等。已将timeBeginPeriod设置为1。在Windows 7上正常工作,按预期工作(没有多余的毫秒)。这种行为是否正常/可以修复?

#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "winmm.lib")

LARGE_INTEGER Frequency;

long long int GetCurrent()
{
    LARGE_INTEGER counter;

    QueryPerformanceCounter(&counter);

    return (1000000 * counter.QuadPart / Frequency.QuadPart);
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    timeBeginPeriod(1);

    QueryPerformanceFrequency(&Frequency);

    const unsigned int count = 1000;

    long long int buffer[count];

    long long int lastTime = GetCurrent(), currentTime;

    for (unsigned int i = 0; i < count; i++)
    {
        currentTime = GetCurrent();

        buffer[i] = currentTime - lastTime;

        lastTime = currentTime;

        Sleep(1);
    }

    timeEndPeriod(1);

    FILE *file = fopen("log.txt", "w");

    for (unsigned int i = 0; i < count; i++)
        fprintf(file, "%ld\n", buffer[i]);

    fclose(file);

    return EXIT_SUCCESS;
}

7
“Sleep” 函数保证至少睡眠您所要求的时间,可能会更久,受调度器的支配;这一点历来如此,您不能依靠它的精确性,特别是在其范围的较低端。” - Matteo Italia
我理解这一点,但在Windows 7(以及可能在其他早期系统上),使用设置了平均值的timeBeginPeriodSleep大约是请求的值。但在Windows 8.1上,它总是会增加+1毫秒的超额时间。我认为这种行为相当奇怪。 - Demion
9
Windows 8.1 中对定时器进行了调整。使用这段代码可能会获得 1 毫秒和 2 毫秒的间隔,如果能使用无限速度调用 Sleep() 就更好了,但不可能实现。有时会丢失 1 毫秒,这是官方文档记录的行为。应该使用实际的定时器代替依赖于 Sleep(),以便 Windows 能够正确处理。timeSetEvent() 是遗留的,CreateTimerQueueTimer() 更加现代化。 - Hans Passant
1
尝试使用 NtDelayExecution - user541686
1
看一下 QueryPerformanceCounter 和 QueryPerformanceFrequency。它们可能会给你所需的分辨率。如果你想要非常高分辨率的睡眠,你需要考虑执行代码所花费的时间。 - cup
显示剩余3条评论
1个回答

0

NtDelayExecution 的解决方法,感谢 Mehrdad

static NTSTATUS (__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS (__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDelayExecution");

LARGE_INTEGER delay;

unsigned int milliseconds = 1;

delay.QuadPart = (milliseconds > 1) ? -10000LL * (milliseconds - 1) : -1LL;

NtDelayExecution(false, &delay);

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