计时器在交叉线程中不起作用

Sha*_*yar 5 c# multithreading timer winforms

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
Run Code Online (Sandbox Code Playgroud)

在新的thead:

    //after performing some tasks, it enables the timers
    KeepMeAliveTimer.Enabled = true;  //timer 1
    KeepMeAliveTimer.Start();
    timer1.Enabled = true;   //timer 2
    timer1.Start();
Run Code Online (Sandbox Code Playgroud)

但它没有启动Timer的tick事件,甚至没有抛出任何异常.

第二种方法:

但是当我初始化并启用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();  
Run Code Online (Sandbox Code Playgroud)

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

Han*_*ant 10

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

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

或者使用System.Threading.Timer或System.Timers.Timer,它们不依赖于消息循环.你必须正确地互锁,他们的Elapsed事件或回调在另一个线程上运行.哪种解决方案往往会产生另一个问题.