【问题标题】:Can i expect anything from Windows-API's Sleep function?我可以从 Windows-API 的睡眠功能中得到什么吗?
【发布时间】:2020-08-22 15:14:49
【问题描述】:

我试图在 CPP 中为 Windows(我的机器有 Windows 10)制作一个简单的图形程序,但我正在努力锁定帧速率。

这是我的问题的简单说明:

inline LARGE_INTEGER
get_wall_clock()
{
    LARGE_INTEGER result;
    QueryPerformanceCounter(&result);
    return result;
}

static LARGE_INTEGER frequency;

inline float
get_seconds_elapsed(LARGE_INTEGER begin, LARGE_INTEGER end)
{
    return (float)(end.QuadPart - begin.QuadPart) / (float)frequency.QuadPart;
}

int main()
{
    bool can_sleep = (timeBeginPeriod(1) == TIMERR_NOERROR);
    QueryPerformanceFrequency(&frequency);
    int target_HZ = 60;
    float target_seconds_per_frame = 1.0f / (float)target_HZ;
    LARGE_INTEGER last_counter = get_wall_clock();
    while(true)
    {
        do_something();

        LARGE_INTEGER end_frame = get_wall_clock();
        float seconds_of_work = get_seconds_elapsed(last_counter, end_frame);
        float seconds_of_frame = seconds_of_work;
        if(seconds_of_work < target_seconds_per_frame)
        {
            if(can_sleep)
            {
                int ms_to_sleep = (int)(1000.0f * (target_seconds_per_frame - seconds_of_work));
                if(ms_to_sleep)
                {
                    Sleep(ms_to_sleep);
                }
            }
            float frame_duration = get_seconds_elapsed(last_counter, get_wall_clock());
            Assert(frame_duration < target_seconds_per_frame);
            while(seconds_of_frame < target_seconds_per_frame)
                seconds_of_frame = get_seconds_elapsed(last_counter, get_wall_clock());
        }
        last_counter = get_wall_clock();
    }
    timeEndPeriod(1);
}

我的问题是断言:

Assert(frame_duration < target_seconds_per_frame);

几乎总是开火。

我尝试对睡眠的毫秒数进行一些调整,甚至让它只睡眠所需的 90% 的毫秒 - 但它似乎没有帮助。

但真正奇怪的是以下...当我尝试通过以下方法测量睡眠功能实际睡眠的时间时:

LARGE_INTEGER sleep_start = get_wall_clock();
Sleep(ms_to_sleep);
float seconds_slept = get_seconds_elapsed(sleep_start, get_wall_clock());

我发现它有时会比请求的毫秒数多睡 waaayyy。看到 10-20 毫秒的差异并不少见(我曾经有一段时间 ms_to_sleep 是 12 岁,它实际上睡了 30 多毫秒)。

我在这里有什么明显的遗漏吗? 我知道根据文档,睡眠不能保证在请求的时间内睡眠,但我认为 timeBeginPeriod +ms_to_sleep 的地板可以覆盖...

有没有其他方法可以可靠地等待帧结束(除了循环)?

提前谢谢各位...

【问题讨论】:

    标签: c++ windows sleep frame-rate msdn


    【解决方案1】:

    我在这里有什么明显的遗漏吗?

    坦率地说,是的。你没有看说明书。来自docs

    经过休眠间隔后,线程就可以运行了。如果您指定 0 毫秒,线程将放弃其时间片的剩余部分但保持就绪状态。 请注意,不能保证就绪线程会立即运行。因此,线程可能要等到休眠间隔结束后的某个时间才会运行。有关详细信息,请参阅调度优先级。

    Sleep 不会按照您要求的时间进入睡眠状态。

    【讨论】:

    • 哦,即使我检查了 beginTimePeriod(1) 的调用是否成功?
    • 也 - 我可以期望它一些级别的准确性吗?
    • @ItzikShneorson 时钟的分辨率高于我在答案中引用的效果
    • @ItzikShneorson 我不知道 Windows 中的任何细节,但线程何时继续由调度程序决定,通常你几乎无法控制。
    • 嗯...但无论如何:我认为 10-20 毫秒(可能大约 26,843,540 个处理器的周期)是足够长的时间...
    猜你喜欢
    • 2021-04-12
    • 2013-02-06
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 2021-12-27
    • 2010-11-11
    • 2011-02-03
    相关资源
    最近更新 更多