[英]Invoke timer from background thread
我想做的事。 我想SomeMethod将被定期调用。 因此,我希望计时器在背景线程方法传递后从背景线程启动。 _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);
一切正常。 有人可以解释给我什么把戏吗?
您有些混乱了。
如果您想要一个在后台线程上触发的计时器,则无需创建一个线程来启动它(哪个线程调用Start
方法都没有关系)。 只需使用System.Timers.Timer
,每个Elapsed
事件将在线程池线程上发生。
如果您希望在UI线程上触发一个计时器,因为看起来您正在使用WPF,则应使用System.Windows.Threading.DispatcherTimer
,而不要使用您一直在使用的Windows Forms计时器。 您应该在特定的UI线程上创建计时器(即,调用new
),并且每个Tick
事件都会在该线程上发生。 同样,从哪个线程调用Start
都没有关系。
这是对代码中发生的情况的解释:您正在非UI线程上启动Windows Forms计时器。 这种计时器要求消息泵在该线程上运行,以便它可以接收消息。 因为它是非UI线程,所以没有消息泵。 使用Dispatcher.Invoke
方法时,将计时器的创建编组回应用程序的主UI线程,这使它可以工作。 但这一切都是多余的。 如果您希望将代码保持原样,只需用DispatcherTimer
替换计时器,然后就可以删除Invoke
调用。
另外,如果您使用的是.NET 4.5,则可以使用await / async来SomeMethod
所有操作(请确保从UI线程调用SomeMethod
):
async Task SomeMethod(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.Run(() => DoAsyncStuff(), ct);
DoUIStuff();
await Task.Delay(TimeSpan.FromMinutes(1), ct);
}
}
MSDN可以为您解释:
注意:Windows Forms Timer组件是单线程的,并且精度限制为55毫秒。 如果需要更高精度的多线程计时器,请使用System.Timers命名空间中的Timer类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.