5

System.Windows.Forms.Timer我的表单中有 2 个全局变量。两者都在表单的构造函数中初始化。但还没有开始。构造函数启动一个新线程,该线程启用并启动两个计时器。显然都是跨线程,但它不会抛出任何跨线程异常。但它甚至不起作用。它不会触发该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

在新主题中:

    //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();  

现在的问题是;如果没有任何异常,为什么第一种方法不起作用?

4

1 回答 1

11

Timer 类是线程安全的,但不是您期望的那样。在工作线程上调用 Start() 方法实际上会启动计时器。该类完成了创建隐藏窗口的工作,因此它可以调用 SetTimer winapi 函数并在完成后接收 WM_TIMER 消息。

但是如果没有人在收听该消息,则无法引发 Tick 事件。你不会,当然你没有在那个线程上调用 Application.Run() 。因此,您不应在工作线程上启动计时器。如有必要,请使用 Control.BeginInvoke 在 UI 线程上启动它。

或者使用 System.Threading.Timer 或 System.Timers.Timer,它们不依赖于消息循环。您确实必须正确联锁,它们的 Elapsed 事件或回调在另一个线程上运行。这是一种倾向于产生另一个问题的解决方案。

于 2013-06-21T21:44:49.463 回答