0

我正在用 C# 开发一个 Chip-8 模拟器,我已经完成了几乎所有方面的部分工作,但我仍然想知道模拟器的速度控制。

我现在正在做的是假设我每秒获得 60 帧,我使用一个以以下方式触发 1/60 秒的计时器(伪代码):

timer_ticked()
{
    for(int i = 0; i < Settings.CyclesPerFrame; i++)
    {
        EmulateCycle();
    }

    if (IsDrawFlagSet)
    {
        DrawGraphics();
    }
}

我正在使用一个名为 microtimer http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer的高分辨率计时器,我相信计时器不会等待 timer_ticked 完成触发下一个周期(fon 实例,创建一个新线程)我遇到了线程和表单问题,因为尝试使用 GDI 绘制到窗口(使用 control.GetGraphics() 方法)似乎是线程安全的,但试图创建一个 SDLDotNet 方法(只是一个例子)没有。

您认为哪种方法可以最好地控制模拟器的速度,而不会陷入计时器线程的疯狂状态?

PS:模拟器的源码可以在GitHub上找到:https ://github.com/AlFranco/C8POC

谢谢!

4

1 回答 1

0

如果您在完成之前再次调用打勾方法,则问题不在于您的计时器。这是因为处理时间超过了 16.6 毫秒。获得更好的计时器并不能解决您的问题。

也就是说,您可以通过几种方式防止重入。

您可以在输入回调时禁用计时器,并在完成后重新启用它。这将防止多次调用:

timer_ticked()
{
    timer.Enabled = false;
    // do stuff here
    timer.Enabled = true;
}

请注意,这并不能为您提供完美的 16.6 毫秒滴答频率。相反,下一个滴答声将在您启用计时器后 16.6 毫秒(大约)发生。您的实际周期是 16.6 毫秒加上处理所需的时间。

唯一会失败的情况是timer_ticked在下一次滴答发生之前没有调用该方法。

如果您想保证无法获得并发滴答,可以使用 aSystem.Threading.Timer并将其设置为一次性(无周期性信号)。例如:

Timer myTimer = new Timer(timer_tick, null, 16, -1);

最后-1一个参数中的 告诉它不是周期性计时器。它会触发一次并停止。

然后,在你的计时器滴答声中:

timer_tick()
{
    // do stuff
    // restart the timer
    myTimer.Change(16, -1);
}

编辑

如果处理程序仍在处理前一个滴答声,您不能轻易告诉计时器不要发出滴答声。但是,您可以阻止计时器滴答处理程序在后续滴答中执行任何操作。您只需使用Monitor

private object timerLock = new object();
timer_ticked()
{
    if (!Monitor.TryEnter(timerLock))
        return;
    try
    {
        // do stuff here
    }
    finally
    {
        Monitor.Exit(timerLock);
    }
}

这种解决方案的问题在于,如果您的计时器设置为 16 毫秒并且处理程序需要 17 毫秒,那么您的有效更新率将是每 32 毫秒一次,因为第二个滴答基本上被忽略了。你最好使用一次性计时器交易。

另一种可能性是使用 a Stopwatchto time 你的处理程序需要多长时间,并从下一个延迟期中减去它:

timer_ticked()
{
    var sw = Stopwatch.StartNew();
    // do stuff
    timer.Change(16-sw.ElapsedMilliseconds, -1);
}

但这并不是那么简单。如果处理程序完成它的时间超过 16 毫秒,那么您最终会得到一个负延迟。所以你会想要:

var delayTime = Math.Max(0, 16 - sw.ElapsedMilliseconds);
timer.Change(delayTime, -1);

但是同样,如果您的处理程序经常花费比计时器延迟更长的时间,那么这对您没有帮助。您要么必须降低定时器频率(即延长延迟),要么优化处理代码。

于 2013-04-02T16:03:09.667 回答