std :: this_thread :: sleep_for睡眠时间过长 [英] std::this_thread::sleep_for sleeps for too long

查看:633
本文介绍了std :: this_thread :: sleep_for睡眠时间过长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以通过以下示例来说明问题所在吗?

Can anyone tell what the problem with following example is?

每秒产生65帧而不是300帧.

It produces 65 instead of 300 frames per second.

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>

#include <Thread>
#include <Chrono>
#include <String>

int main(int argc, const char* argv[]) {

    using namespace std::chrono_literals;

    constexpr unsigned short FPS_Limit = 300;

    std::chrono::duration<double, std::ratio<1, FPS_Limit>> FrameDelay = std::chrono::duration<double, std::ratio<1, FPS_Limit>>(1.0f);

    unsigned int FPS = 0;

    std::chrono::steady_clock SecondTimer;
    std::chrono::steady_clock ProcessTimer;

    std::chrono::steady_clock::time_point TpS = SecondTimer.now();
    std::chrono::steady_clock::time_point TpP = ProcessTimer.now();

    while (true) {

        // ...

        // Count FPS

        FPS++;

        if ((TpS + (SecondTimer.now() - TpS)) > (TpS + 1s)) {

            OutputDebugString(std::to_string(FPS).c_str()); OutputDebugString("\n");

            FPS = 0;

            TpS = SecondTimer.now();
        }

        // Sleep

        std::this_thread::sleep_for(FrameDelay - (ProcessTimer.now() - TpP));    // FrameDelay minus time needed to execute other things

        TpP = ProcessTimer.now();
    }

    return 0;
}

我猜想它与std::chrono::duration<double, std::ratio<1, FPS_Limit>>有关,但是当它乘以FPS_Limit时,每秒会产生正确的1帧.

I guess it has something to do with std::chrono::duration<double, std::ratio<1, FPS_Limit>>, but when it is multiplied by FPS_Limit the correct 1 frames per second are produced.

请注意,每秒300帧的限制仅是示例. 可以用任何其他数字代替,并且程序仍然会休眠太长时间.

Note that the limit of 300 frames per second is just an example. It can be replaced by any other number and the program would still sleep for way too long.

推荐答案

简而言之,问题在于您完全使用了std::this_thread::sleep_for.或者,与此有关的任何一种睡眠".睡眠以限制帧速率完全是错误的.

In short, the problem is that you use std::this_thread::sleep_for at all. Or, any kind of "sleep" for that matter. Sleeping to limit the frame rate is just utterly wrong.

睡眠功能的目的是,好吧……我不诚实.完全没有很好的用途,实际上在每种情况下,使用不同的机制都是更好的选择.

The purpose of sleep functionality is, well... I don't know to be honest. There are very few good uses for it at all, and in practically every situation, a different mechanism is better.

std::this_thread::sleep_for的作用(给出或进行了几行健全性测试和错误检查)是,它调用Win32 Sleep函数(或在不同的OS上,使用不同的类似函数,例如nanosleep ).

What std::this_thread::sleep_for does (give or take a few lines of sanity tests and error checking) is, it calls the Win32 Sleep function (or, on a different OS, a different, similar function such as nanosleep).

现在,Sleep会做什么?它在操作系统的一本小红皮书中记下您的线程需要在将来的某个时间重新准备好,然后使您的线程未就绪.未准备就绪意味着您的线程不在要安排获取CPU时间的候选列表中.

Now, what does Sleep do? It makes a note somewhere in the operating system's little red book that your thread needs to be made ready again at some future time, and then renders your thread not-ready. Being not-ready means simply that your thread is not on the list of candidates to be scheduled for getting CPU time.

有时,最终,硬件计时器将触发中断.这可以是具有令人尴尬的默认分辨率的定期计时器(Windows 8之前的版本),也可以是可编程的一键式中断(无论如何).您甚至可以调整计时器的分辨率,但这是 global 的事情,它会大大增加上下文切换的次数.另外,它不能解决 actual 问题.当操作系统处理中断时,它会在书中查看需要准备哪些线程,然后执行该操作.

Sometimes, eventually, a hardware timer will fire an interrupt. That can be a periodic timer (pre Windows 8) with an embarrassingly bad default resolution, or programmable one-shot interrupt, whatever. You can even adjust that timer's resolution, but doing so is a global thing which greatly increases the number of context switches. Plus, it doesn't solve the actual problem. When the OS handles the interrupt, it looks in its book to see which threads need to be made ready, and it does that.

但是,不同的是,它与运行线程相同.它只是再次运行(也许是一段时间)的候选人.

That, however, is not the same as running your thread. It is merely a candidate for being run again (maybe, some time).

因此,存在计时器粒度,测量结果不准确以及计划安排...这对于短期的定期间隔来说非常非常不适合.同样,已知不同的Windows版本对调度程序的粒度的取舍也不同.

So, there's timer granularity, inaccuracy in your measurement, plus scheduling... which altogether is very, very unsuitable for short, periodic intervals. Also, different Windows versions are known to round differently to the scheduler's granularity.

解决方案:请勿入睡.启用垂直同步,或将其留给用户启用.

Solution: Do not sleep. Enable vertical sync, or leave it to the user to enable it.

这篇关于std :: this_thread :: sleep_for睡眠时间过长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆