任何人都可以说出下面的示例是什么问题吗?
它每秒产生65帧而不是300帧。
#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帧。
请注意,每秒300帧的限制仅是示例。可以用其他任何数字代替它,并且程序仍然会休眠太长时间。
简而言之,问题在于您完全使用了std::this_thread::sleep_for
。或者,与此有关的任何一种“睡眠”。睡眠以限制帧速率完全是错误的。
睡眠功能的目的是,好吧……我不诚实。几乎没有很好的用途,实际上在每种情况下,使用不同的机制会更好。
std::this_thread::sleep_for
的作用(给予或进行了几行健全性测试和错误检查)是,它调用Win32 Sleep
函数(或在不同的OS上,使用不同的类似函数,例如nanosleep
) 。
现在,Sleep
是做什么的?它在操作系统的一本小红皮书中记下您的线程需要在将来的某个时间重新准备好,然后渲染线程not-ready。未准备就绪意味着您的线程不在要安排获取CPU时间的候选列表中。
有时,最终,硬件计时器将触发中断。这可以是具有令人尴尬的默认分辨率的定期计时器(Windows 8之前的版本),也可以是可编程的单触发中断。您甚至可以调整计时器的分辨率,但这是一件很麻烦的事情,它会大大增加上下文切换的次数。另外,它不能解决actual问题。当操作系统处理中断时,它会在书中查看需要准备哪些线程,然后执行此操作。但是,与运行线程相同。它仅是再次运行(可能需要一段时间)的候选人。
因此,存在计时器粒度,测量结果不准确以及计划...这对于短期的周期性间隔来说非常非常不适合。另外,已知不同的Windows版本对调度程序的粒度的取舍也不同。解决方案:不要睡觉。启用垂直同步,或将其留给用户启用。