Shaharyar
Shaharyar

Reputation: 12439

Timer is not working in cross threads

I have 2 global System.Windows.Forms.Timer in my form. Both are initialized in form's constructor. But not started yet. Constructor starts a new thread and that thread enables and starts both of the timers. Obviously it is all cross threading, but it doesn't throw any cross-thread exception. But it doesn't even work. It does not fire the Timer.Tick method. Here is the code:

1st Method:

In form constructor:

    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

In new thead:

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

But it is not firing up Timer's tick events and not even throwing any exception.

2nd Method:

But when I initialized and enabled the Timers in the same thread (Main Thread) they are working perfectly:

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

Now the question is; Why the first method is not working if there is not even any exception?

Upvotes: 5

Views: 3789

Answers (1)

Hans Passant
Hans Passant

Reputation: 941495

The Timer class is thread-safe but not in the way you expect it. Calling the Start() method on worker thread does actually start the timer. The class goes through the effort of creating a hidden window so it can call the SetTimer winapi function and receive the WM_TIMER message when it is done.

But the Tick event cannot be raised if nobody is listening for that message. You won't be, surely you didn't call Application.Run() on that thread. You should therefore not start a timer on a worker thread. Use Control.BeginInvoke if necessary to get it started on the UI thread.

Or use a System.Threading.Timer or System.Timers.Timer, they don't depend on a message loop. You do have to interlock properly, their Elapsed event or callback run on yet another thread. Which is the kind of solution that tends to create another problem.

Upvotes: 11

Related Questions