从后台线程调用计时器

时间:2013-10-01 06:08:49

标签: c# multithreading timer

我想做什么。我想定期调用SomeMethod。因此,我希望计时器将在后台线程方法体传递后从backgroung线程启动。调用了_timer.Start(),但TickHandler没有;

代码:

using Timer = System.Windows.Forms.Timer;

class TestTimer
    {
        private Timer _timer;
        private Thread _thread;

        public TestTimer()
        {
            // create and initializing timer. but not started!
            _timer = new Timer();
            _timer.Tick += TickHandler;
            _timer.Interval = 60000; // 1 minute

            // create and start new thread
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }

        private void TickHandler(object sender, EventArgs e)
        {
            // stop timer
            _timer.stop();

            //some handling

            // run background thread again
            _thread = new Thread(SomeMethod);
            _thread.Start();
        }   

        private void SomeMethod()
        {
            // some operations

            // start timer!
            TimerStart();
        }

        private void TimerStart()
        {
            _timer.Start();
        } 
    }

通过猴子方法,我发现如果像这样添加委托

internal delegate void TimerDelegate();

并替换字符串

TimerStart(); 

Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);

一切正常。有人可以解释一下诀窍是什么?

2 个答案:

答案 0 :(得分:4)

你的事情有些混乱。

如果你想在后台线程上触发的计时器,你不必创建一个线程来启动它(哪个线程调用无关紧要) Start方法)。只需使用System.Timers.Timer,每个Elapsed事件都将发生在线程池线程上。

如果你想在 UI线程上触发的计时器,因为看起来你正在使用WPF,你应该使用System.Windows.Threading.DispatcherTimer,而不是您一直在使用的Windows窗体计时器。您应该创建特定UI线程上的计时器(即调用new),并且每个Tick事件都将在该线程上发生。同样,您调用Start的哪个主题无关紧要。

以下是对代码中发生的事情的解释:您正在非UI线程上启动Windows窗体计时器。这种计时器需要在该线程上运行消息泵,以便它可以接收消息。因为它是一个非UI线程,所以没有消息泵。当您使用Dispatcher.Invoke方法时,您将计时器的创建封送回应用程序的主UI线程,这使其工作。但这完全是多余的。如果您希望保持代码不变,只需将计时器替换为DispatcherTimer,然后您就可以删除Invoke来电。

或者,如果您使用的是.NET 4.5,则可以使用await / async来使这一切变得更加容易(请务必从UI线程调用SomeMethod):

async Task SomeMethod(CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        await Task.Run(() => DoAsyncStuff(), ct);

        DoUIStuff();

        await Task.Delay(TimeSpan.FromMinutes(1), ct);
    }
}

答案 1 :(得分:0)

MSDN可以为您解释:

  

注意Windows窗体计时器组件是单线程的,并且是   限制精度为55毫秒。如果你需要   多线程计时器具有更高的准确性,使用Timer中的类   System.Timers名称空间。