我的表单中有2个全局System.Windows.Forms.Timer
。两者都在表单构造函数中初始化。但尚未开始。构造函数启动新线程,该线程启用并启动两个计时器。显然它都是交叉线程,但它不会抛出任何跨线程异常。但它甚至不起作用。它不会触发Timer.Tick
方法。这是代码:
第一种方法:
在表单构造函数中:
KeepMeAliveTimer = new Timer(); //timer 1
KeepMeAliveTimer.Interval = 15000;
KeepMeAliveTimer.Tick += KeepMeAlive;
timer1 = new Timer(); //timer 2
timer1.Interval = 15000;
timer1.Tick += timer1_Tick;
//started a new thread
在新的thead中:
//after performing some tasks, it enables the timers
KeepMeAliveTimer.Enabled = true; //timer 1
KeepMeAliveTimer.Start();
timer1.Enabled = true; //timer 2
timer1.Start();
但它没有触发Timer的嘀嗒事件,甚至没有抛出任何异常。
第二种方法:
但是当我在同一个线程(主线程)中初始化并启用Timers
时,它们完美地运行了:
KeepMeAliveTimer = new Timer(); //timer 1
KeepMeAliveTimer.Interval = 15000;
KeepMeAliveTimer.Tick += KeepMeAlive;
KeepMeAliveTimer.Enabled = true;
KeepMeAliveTimer.Start();
timer1 = new Timer(); //timer 2
timer1.Interval = 15000;
timer1.Tick += timer1_Tick;
timer1.Enabled = true;
timer1.Start();
现在的问题是;如果没有任何异常,为什么第一种方法不起作用?
答案 0 :(得分:10)
Timer类是线程安全的,但不是你想象的那样。在工作线程上调用Start()方法实际上启动了计时器。该类经历了创建隐藏窗口的工作,因此它可以调用SetTimer winapi函数并在完成后接收WM_TIMER消息。
但是如果没有人正在侦听该消息,则无法引发Tick事件。你不会,你肯定没有在该线程上调用Application.Run()。因此,您不应该在工作线程上启动计时器。如有必要,请使用Control.BeginInvoke在UI线程上启动它。
或者使用System.Threading.Timer或System.Timers.Timer,它们不依赖于消息循环。你必须正确地联锁,他们的Elapsed事件或回调在另一个线程上运行。哪种解决方案往往会产生另一个问题。