睡眠/等待而不消耗CPU

所以我在Windows上模拟这个智能手机应用程序。 这是一个运行它的逻辑和以1/60速率绘制方法的游戏。 以毫秒为单位,这是16.6667

我实现了这个游戏循环:

  private const double UPDATE_RATE = 1000d / 60d; private void GameLoop() { double startTime; while (GetStatus() != GameStatus.NotConnected) { startTime = Program.TimeInMillis; //Update Logic while (Program.TimeInMillis - startTime <= UPDATE_RATE) { //Thread.Yield(); it consumed CPU before adding this too, adding this had no effect Thread.Sleep(TimeSpan.FromTicks(1));//don't eat my cpu } } Debug.WriteLine("GameLoop shutdown"); } 

Program.TimeInMillis来自NanoStopwatch类,以NanoStopwatchNanoStopwatch返回时间。 这很有用,因为这个游戏循环必须非常准确才能让一切正常。

您可能知道, Thread.Sleep将消耗大量的CPU。 可能是因为它需要int millis将我的TimeSpan转换为0毫秒。

我最近遇到了一个名为WaitHandle东西,但我看到的一切都是使用int millis 。 我真的需要让这个准确,所以我实际上需要double millis microseconds/nanosecondsmicroseconds/nanoseconds

C#中有什么东西可以让我Wait x微秒。 我不介意自己创造一些东西(就像我为NanoStopwatch所做的NanoStopwatch ),但我需要指向正确的方向。 在互联网上发现了很多东西,但是所有东西都使用int millis ,这对我来说不够准确。

我运行了一些测试来改变Sleep以使用类似: UPDATE_RATE - (Program.TimeInMillis - startTime)这不会使我的游戏循环准确。

我希望一切都足够清楚,如果您需要更多信息,请发表评论。

tl; dr – 有没有办法让线程在C#等待microseconds/nanoseconds ? 我的游戏循环需要准确,毫秒对我来说不够准确。

提前致谢!

您需要硬件支持才能达到此类准确性。 产生中断和触发代码以完成工作的信号。 在Windows中有两个明显的候选人可以使用这样的信号。

第一个是VSYNC中断,一个video设备驱动程序实现细节。 它出现在显示器刷新率下,液晶显示器通常为60赫兹。 正是你要求的当然,没有巧合。 大多数程序员使用DirectX来实现游戏图形,你要求它使用D3DPRESENT设置的信号。 否则很不清楚你为什么不在问题中使用它,而是你应该追求的解决方案。

第二个是时钟中断。 那是你抱怨的那个。 在Windows上是一个大问题,这是唤醒线程调度程序并获取代码运行的信号。 它直接负责Thread.Sleep()的准确性。 在发生时钟中断并且调度程序将线程重新置于活动状态之前,hibernate的代码无法再次开始运行。 没有其他办法可以做到这一点,处理器通过HLT指令物理关闭,不消耗功率,只能通过中断唤醒。 默认情况下,时钟中断每秒传输64次。 每15.625毫秒一次。 它往往会被司机和其他东西修补,他们经常将它重新编程为10毫秒。 提供免费软件并与自己的产品相媲美的公司使其低至1毫秒。

如果由于某种原因无法驯服DirectX,那么您还需要做什么。 Pinvoke timeBeginPeriod(1)获得1毫秒的精度。 从技术上讲,使用NtSetTimerResolution()可以降低到500微秒,但是当拨号进入时它会很低。 并且请记住,您无法始终如一地维持此类速率,线程调度量,垃圾收集暂停,硬分页错误以及以实时优先级运行其代码的令人讨厌的设备驱动程序所需的时间要长得多。