高精度的睡眠/等待.net

背景:我已经在F#/。net中编写了一个gameboy模拟器。 在gameboy中,vblank(〜fps)约为60赫兹,与游戏速度相关,因此仿真器运行速度尽可能接近60 fps非常重要。

由于现代计算机可以运行我的模拟器比60 fps快很多,我需要减慢模拟器。 我目前的做法是计算两个VBlanks之间的时间,然后等待这个vblank时间的剩余时间。

问题随着如何等待而不忙循环CPU。 由于我通常需要等待几个毫秒(有时更多,有时更less),内置的Thread.sleep函数不是一个好的select,因为除非指定0等待时间,它将睡眠至less〜15毫秒,这是方式长(和不准确)。 我目前的做法是使用睡眠(0),这真的只是一个奇特的螺旋锁(其他线程可能运行,但你仍然最大的CPU)。

什么是解决这个问题的正确方法? 我正在考虑等待计时器释放的信号量,但计时器是否能够提供所需的时间分辨率? 而且这不仅仅是一个梦幻般的睡眠?

编辑:这被标记为什么线程睡眠方法是最精确的重复:Monitor.Wait VS System.Timer VS DispatchTimer vs Threading.Timer,但我认为这是精度较低的问题,更多的是find一个适当的解决scheme一个严密的游戏循环。

正如你所指出的那样,默认的系统定时器不够快 – 15.6ms能够达到60 FPS,但不是“每帧恒定的时间”或者任何接近这个的时间。

一个解决方案是使用繁忙循环,但是,如此漫长的等待时间,这是一个巨大的浪费(有趣的是,一种方法是“太短”,而另一种是“太长”:))。

另一个选择是使用timeBeginPeriodhttps://msdn.microsoft.com/en-us/library/windows/apps/dd757624 ( v= timeBeginPeriod ) timeBeginPeriod )更改系统计时器 – 您将需要使用P /调用访问这个API,但它会让你睡得更准确。 或者更好的是,使用Timer设置为〜16.7ms。

如果你不想搞砸,只需要一个计时器( System.Threading.Timer ,而不是Windows窗体),并将其设置为15ms。 虽然这不会给你准确的60 FPS,它应该平均在每秒约64次更新,这应该是足够接近,不容易注意到。 由于定时器回调从“睡眠”中分离出来(没有真正的睡眠,但是在等待定时器启动的时候你没有做CPU工作),它不会像一个窗体那样跳过或者加倍帧。 请注意,这隐含地涉及多线程,所以请确保正确使用同步。