在C#中构建更新循环

时间:2015-11-19 01:22:55

标签: c# loops game-engine thread-sleep game-loop

我需要在C#中实现一个更新循环,类似于游戏引擎中的更新循环,它定期执行一系列任务。 我已经搜索了一些搜索文档,并从游戏编程模式中阅读了一些SO讨论和THIS,但是我的情况可能有点不同,我并没有找到解决问题的方法。这是我的情况:

1-更新循环必须每秒处理其任务1000次(1000不是硬约束,如果循环运行999或1001,那么无论如何都会没问题)

2-任务是同步的,所以如果我的task1需要100秒才能执行,task2将等待100秒

3-程序仅在Windows上执行,因此如果需要,我可以使用PInvoke调用Windows本机函数

4-如果启动循环的线程与执行它的线程相同并且在其中保持阻塞,那就没关系

5-如果没有要执行的作业,或者如果处理作业的速度超过每秒1000次,则循环不得占用整个核心。基本上,如果需要,循环可以休眠/等待(稍后会详细介绍)

我在这里HERE找到了一个在C#中实现事件循环的解决方案,但是这里的任务是异步的,它违反了第2点。

我还发现了HERE一个使用System.Timers.Timer来执行任务的解决方案。

但是:

Windows不是实时操作系统,默认情况下,计时器的频率约为15毫秒,这意味着每秒只有66次更新。

我从HERE知道定时器可以设置为1ms,但由于设置是全局的,因此可能会产生其他程序的问题,如果可能的话我想避免这种情况。

最后我看到HERE我可以使用Windows消息泵来使用空闲事件触发我的更新,但是我没有发现它是否可以被激活1000次或者是否有副作用喜欢生成垃圾。

到目前为止,我已经考虑过这些"解决方案" (因为它们违反了第1点或第5点而无效)

while(isRunning)
{
   startTime = stopWatch.Elapsed;

   ProcessTasks();

   Thread.sleep(timeToWait - (stopWatch.Elapsed - startTime)); //variant below
}

但由于默认的最小睡眠时间约为15毫秒(或远远超过1毫秒),因此无法使用Thread.sleep,所以我试过

while ((stopTicks = this.stopWatch.ElapsedTicks - startTicks) < this.sleepTicks)
{
   Thread.SpinWait(x); //OR Thread.Yield();
}

其中x是一个确保足够精度并在Timespan结构中使用常量的变量,我可以用毫秒或其他时间单位转换刻度 并使循环每秒执行1000次。然而,这种方法最终消耗了整个核心(100%核心使用率)这很糟糕,因为这段代码可能在电池供电的笔记本电脑上运行,而且一般来说它看起来并不干净(但我可能错了#&# 34;清洁&#34;陈述)。代码也是实际代码的简化。

所以这是我的情况,任何想法或我错过了什么?

另外:我注意到的另一件事是像Unreal,Unity3d等游戏引擎设法获得超过66fps(所以睡眠/等待不到15ms),同时如果它不是消耗整个核心需要。当然他们的核心主要是用C ++而不是C#编写的,但他们是如何做到的呢?

非常感谢

0 个答案:

没有答案