我该如何在 System.Threading.Timer 的回调函数中更改时间间隔?

9

我怎样才能在 System.Threading.Timer 的回调函数中更改时间间隔?

这样做是正确的吗?

但并没有发生变化。

public class TestTimer
{
    private static Timer _timer = new Timer(TimerCallBack); 

    public void Run()
    {
        _timer.Change(TimeSpan.Zero, TimeSpan.FromMinutes(1));
    }

    private static void TimerCallBack(object obj)
    {
        if(true)
            _timer.Change(TimeSpan.Zero, TimeSpan.FromMinutes(10));
    }

}

1
@Mitch Wheat,这是有一些很好的原因的有效性,例如测试? - crypted
1
Mitch,这只是一个例子,请不要太在意。哈哈 - mrbrooks
只是因为你需要,加1。 - Randall Deetz
2个回答

13

这行代码会导致无限递归:

if(true)
    _timer.Change(TimeSpan.Zero, TimeSpan.FromMinutes(10));

第一个参数会强制执行 TimerCallBack。因此它会一遍又一遍地无限执行。

解决方法是:

if(true)
    _timer.Change(TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));

5
问题在于你对Change的调用指定了下一个调用应该立即发生。如果你要每次调用Change,你可以使用Timeout.Infinite(它只是常量-1)来告诉它在下一次之后避免重复执行 - 但它仍然会继续触发,因为在下一次时,你重新设置了它。例如:
using System;
using System.Threading;

static class Program
{
    private static Timer timer = new Timer(TimerCallBack); 

    public static void Main()
    {
        timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1));
        Thread.Sleep(10000);

    }

    private static void TimerCallBack(object obj)
    {
        Console.WriteLine("{0}: Fired", DateTime.Now);
        timer.Change(TimeSpan.FromSeconds(3),
                     TimeSpan.FromMilliseconds(Timeout.Infinite));
    }
}

另外,你可以只改变一次,然后不再修改:
using System;
using System.Threading;

static class Program
{
    private static Timer timer = new Timer(TimerCallBack); 
    private static bool changed = false;

    public static void Main()
    {
        timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1));
        Thread.Sleep(10000);

    }

    private static void TimerCallBack(object obj)
    {
        Console.WriteLine("{0}: Fired", DateTime.Now);
        if (!changed)
        {
            changed = true;
            TimeSpan interval = TimeSpan.FromSeconds(3);
            timer.Change(interval, interval);
        }
    }
}

请注意,在上述示例中,无论哪种情况都没有使用初始间隔(1秒),因为我们立即调用了Change - 如果您真的想在第一次调用之前设置不同的时间,请不要在对Change的初始调用中使用TimeSpan.Zero

只是为了记录,当然你可以使用-1表示“无限”,但文档确实说你可以使用Timeout.Infinite,我认为这更清楚地显示了意图。;) - James Wilkins
@JamesWilkins:没错,我会修改的。不过如果Timeout.Infinite是一个TimeSpan类型的话,那就更清晰了——Timer.Change(int,int)的文档中提到了Timeout.Infinite,但是Timer.Change(TimeSpan, TimeSpaan)的文档却没有。 - Jon Skeet
是啊,那里的一致性真是让人爱不释手,哈哈。;) 其实一点也不惊讶,早就预料到了,还有其他无用的文档信息。 - James Wilkins
1
Timer.Change(TimeSpan, TimeSpan)中,如果需要无限值,则可以使用Timeout.InfiniteTimeSpan字段。 - Sarrus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接