无需消耗CPU即可休眠/等待 [英] Sleep/Wait without consuming CPU

查看:50
本文介绍了无需消耗CPU即可休眠/等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在将此智能手机应用程序模拟为Windows.这是一款以 1/60 速率运行其逻辑并绘制方法的游戏.以毫秒为单位,为 16.6667

So I am simulating this smartphone app to Windows. It's a game that runs it's logic and draw methods at a 1/60 rate. In milliseconds this is 16.6667

我已经实现了这个游戏循环:

I've implemented this game loop:

    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 类,该类以 double 返回以毫秒为单位的时间.这很有用,因为此游戏循环必须非常准确才能使所有功能正常工作.

Program.TimeInMillis comes from a NanoStopwatch class, that return the time in millis in double. Which is useful because this gameloop has to be really accurate to make everything work.

您可能已经知道, Thread.Sleep 将在此处消耗大量CPU.可能是因为它需要 int millis ,这会将我的 TimeSpan 转换为0毫秒.

As you probably know, the Thread.Sleep will consume a lot of CPU here. Probably because it requires int millis which will convert my TimeSpan to 0 milliseconds.

我最近遇到了一个叫做 WaitHandle 的东西,但是我看到的所有东西都使用了 int millis .我确实需要做到这一点,所以我实际上需要 double millis microseconds/nanoseconds .

I recently came across this thing called WaitHandle, but everything I see uses int millis. I really need to make this accurate so I actually need double millis or microseconds/nanoseconds.

C#中是否有任何内容可以让我 Wait 等待x毫秒.我不介意自己创建一些东西(就像我为 NanoStopwatch 做的一样),但是我需要指出正确的方向.在互联网上找到了很多东西,但是所有东西都使用 int millis ,这对我来说不够准确.

Is there anything in C# that allows me to Wait for x amount of microseconds. I don't mind creating something myself (like I did for the NanoStopwatch), but I need to be pointed in the right direction. Found a lot on the internet, but everything uses int millis and that's not accurate enough for me.

我进行了一些测试,将 Sleep 更改为使用以下代码: UPDATE_RATE-(Program.TimeInMillis-startTime)并不能使我的游戏循环更加准确.

I ran some tests changing the Sleep to use something like: UPDATE_RATE - (Program.TimeInMillis - startTime) which isn't making my gameloop accurate.

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

I hope everything is clear enough, if you need more information just leave a comment.

tl; dr-有什么方法可以让线程在 C#中等待 microseconds/nanoseconds 的数量?我的游戏循环需要准确,毫秒对我来说还不够准确.

tl;dr - Is there any way to let a thread wait for an amount of microseconds/nanoseconds in C#? My gameloop needs to be accurate and milliseconds isn't accurate enough for me.

提前谢谢!

推荐答案

您需要硬件支持才能实现这种准确性.生成 interrupt 并触发代码以完成工作的信号.在Windows中,有两种明显的信号可供选择.

You need hardware support for this kind of accuracy. A signal that generates an interrupt and trigger code to get the job done. There are two obvious candidates for such a signal in Windows.

第一个是VSYNC中断,这是视频设备驱动程序的实现细节.它以监视器刷新率发生,对于LCD监视器,通常为60赫兹.当然,您所要的不是巧合.大多数程序员使用DirectX来实现游戏图形,您要求它使用

The first one is the VSYNC interrupt, a video device driver implementation detail. It occurs at the monitor refresh rate, usually 60 Hertz for LCD monitors. Just what you are asking for of course, no coincidence. Most programmers use DirectX to implement game graphics, you ask it to use the signal with the D3DPRESENT setting. Otherwise very unclear why you are not using it from the question, but the solution you should pursue.

第二个是时钟中断.那就是你在抱怨的那个.在Windows上很重要,这是唤醒线程调度程序并让代码运行的信号.它直接负责Thread.Sleep()的准确性.直到发生时钟中断并且调度程序将线程放回活动状态后,休眠的代码才能再次开始运行.没有其他方法可以执行此操作,处理器实际上是通过HLT指令关闭的,不消耗任何功率,并且只能通过中断来唤醒.默认情况下,时钟中断每秒滴答64次.每15.625毫秒一次.它通常会被驱动程序修补,诸如此类,他们经常对其重新编程以使其在10毫秒处滴答作响.提供免费软件并在使自己的产品看起来不错的公司中拥有股份的公司a>使其低至1毫秒.

The second one is the clock interrupt. That's the one you are complaining about. A big deal on Windows, that's the signal that wakes up the thread scheduler and gets code to run. It is directly responsible for the accuracy of Thread.Sleep(). Code that sleeps cannot start running again until the clock interrupt occurs and the scheduler puts the thread back into the active state. There's no other way to do it, the processor is physically turned off with the HLT instruction, consuming no power, and can only be woken up with an interrupt. By default, the clock interrupt ticks 64 times per second. Once every 15.625 millisecond. It tends to get tinkered with by drivers and whatnot, they often reprogram it to tick at 10 millisecond. Companies that give out free software and have a stake in making their own products look good make it as low as 1 millisecond.

如果由于某些原因无法驯服DirectX,您还需要做什么.Pinvoke timeBeginPeriod(1)可获得1毫秒的精度.从技术上讲,您可以使用NtSetTimerResolution()降低至500微秒,但这与拨盘的速度一样低.并且要记住,您不能始终如一地维持这样的速率,线程调度量子,垃圾回收暂停,硬分页错误和以实时优先级运行其代码的令人讨厌的设备驱动程序所花费的时间要长得多.

Which is what you need to do as well if you can't tame DirectX for some reason. Pinvoke timeBeginPeriod(1) to get 1 msec accuracy. Technically you can go as low as 500 microseconds with NtSetTimerResolution() but that's a low as the dial will go. And do keep in mind that you can't sustain such rates consistently, thread scheduling quanta, garbage collection pauses, hard paging faults and obnoxious device drivers that run their code at realtime priority take much longer than that.

这篇关于无需消耗CPU即可休眠/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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