同步Forms.Timer和Diagnostics.Stopwatch

时间:2012-01-11 15:50:25

标签: c# .net timer synchronization stopwatch

我有一个函数(比如foo()),它会不时以可变间隔调用。当它被调用时,它会检查时间并相应地采取行动。

我已通过以下方式完成此操作:

  • Forms.Timer对象在需要时调用该函数

  • 在函数中使用Diagnostics.Stopwatch对象来确定时间和决定做什么。

但是我有以下问题:当Timer的回调调用foo()时,秒表对象的ElapsedMilliseconds值通常低于预期值。例如,计时器设置为1000,因此在调用1000毫秒后foo(),但在foo()正文ElapsedMilliseconds内返回900,因此foo的行为就好像经过的时间是900(虽然它应该采取行动A,因为实际上已经过了1000毫秒,但它没有)

在ElapsedMilliseconds与计时器具有一致值的情况下,如何同步计时器和秒表?

编辑:部分代码

一些示例代码解释了我的问题:

//foo is the function that is called by timer's callback
public void foo()
{
    //Let's see what time it is: 
    long currentTime = stopwatch.ElapsedMilliseconds();
    Item = getCurrentItem(currentTime);
    Item.Draw();
}

//this is the callback of timer
private void timer1_Tick(object sender, EventArgs e)
    {
        //set the timer for next time
        timer1.Interval = Intervals[periodIdx++];
        foo();
    }

这应该在每次间隔完成时绘制其他内容,但是因为ElapsedMilliseconds返回的值早于计时器声明,尽管间隔结束,但未绘制下一个项目

2 个答案:

答案 0 :(得分:3)

你得到了很大的不同,因为你在1/64秒间隔内的某个地方启动计时器。你会得到更好的结果:

    private void StartTimers() {
        int tick = Environment.TickCount;
        while (Environment.TickCount == tick) Thread.Sleep(0);
        timer1.Enabled = true;
        stopwatch.Start();
    }

while()循环改善了计时器在1/64计时器开始时启动的几率。只是提高,没有保证。而且你不能对Tick事件发送起来做任何事情,它完全取决于你的UI线程的响应能力。但总是迟到。不要使用此代码,编写代码,这样您就不必关心这些定时器不同步。您可能必须减少计时器的间隔才能实现这一点,但问题并不明确。

答案 1 :(得分:2)

这种方法不会取得太大成功。您没有在同一时间启动每个计时器,并且您没有在同一时间检查它们(计时器触发它的事件和您的代码查询秒表之间有一段时间)。

如果您想要同步,请选择一个计时器,并将所有内容基于它。例如,如果你想使用Forms.Timer,在它的事件处理程序中只需增加一个计数器变量 - 它将告诉你调用处理程序的次数,有效地,Forms.Timer说了多少时间已经过去了。这是一个例子(我将留给你处理计时器滴答的时间足够长,计数器超过long.MaxValue)

public void foo()
{
    Item = getCurrentItem(totalElapsed);
    Item.Draw();
}

long totalElapsed = 0;

private void timer1_Tick(object sender, EventArgs e)
    {
        totalElapsed += timer1.Interval;
        //set the timer for next time
        timer1.Interval = Intervals[periodIdx++];
        foo();
    }