1

I have a Timer that does several things

private System.Threading.Timer _xTimer = new System.Threading.Timer(new TimerCallback(XTimerHandler), null, 0, _xTimerPollingInterval);

private void XTimerHandler(object param)
{
    //some code.
}

I have a function which stops the timer:

private void Stop()
{
     //some code.
     if (_xTimer != null)
     {
        ManualResetEvent timerDisposeHandler = new ManualResetEvent(false);
        _xTimer.Dispose(timerDisposeHandler);
        _dataProcessingTimer = null;
        //wait for dispose end.
        timerDisposeHandler.WaitOne();

     }
}

Something very strange is going on!

Sometimes all the GUI hangs on timerDisposeHandler.WaitOne(); (but only sometimes, and I could not see a pattern that repeats itself where it happens, it just dynamically)

Has anyone encountered a similar problem and solved it?

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
Hodaya Shalom
  • 4,327
  • 12
  • 57
  • 111
  • Have you verified these conditions from [MSDN](http://msdn.microsoft.com/en-us/library/b97tkt95(v=vs.110).aspx)? : `The timer is not disposed until all currently queued callbacks have completed.` and then `If the callback uses the Change method to set the dueTime parameter to zero, a race condition can occur`. This might explain why this happens erratically - it depends on what is in the queue at the time of the initial `Dispose()` – StuartLC Oct 01 '14 at 06:52
  • You cannot wait on the UI thread because it is an STA thread. If you debug you should get a debug assistant warning – Peter Ritchie Oct 01 '14 at 07:00
  • Do you happen to do anything with the UI from the timer callback? – Peter Ritchie Oct 01 '14 at 07:55
  • Odds for deadlock are quite high if the timer's callback method is doing anything non-trivial. Just an Invoke() call is enough. Use the debugger's Debug + Windows + Threads to find out what the threads are doing. With the expectation that you find XTimerHandler() back in the call stack of one of them. Deadlocked because the UI thread is stuck in the WaitOne() call. – Hans Passant Oct 01 '14 at 10:25

1 Answers1

2

Blocking the UI is effectively unsupported. While there are wait routines that are "supported" on the UI thread (which means they recognize there is a message pump and pump messages while you're waiting) it's not a good idea to do in general.

First, you're blocking the UI. Yes, some message pumping can occur in certain circumstances, but do you really want the UI thread processing messages and waiting? Recipe for disaster if you're not really, really careful.

Let's take a simple scenario. Let's say that you've done your due diligence when writing your Timer callback (because you've chosen System.Threading.Timer and not "System.Windows.Forms.Timer" which actually runs the Tick event handler on the UI thread) and have chosen to marshal data back to the UI thread with Control.Invoke (or Dispatcher.Invoke with WPF, you haven't specified what type of Windows application you're talking about). Conceptually you've got a Stop method that disposes the Timer and stops callbacks. The Dispose methods for Timer are documented as saying that the callback can be called after Dispose is called and thus a race condition, but also, there may be a callback being invoked at the same time you called Dispose. Both of these scenarios mean that between Dispose and WaitOne (or really just before WaitOne) your Timer callback may make that call to Invoke. Invoke is blocking and waits for the UI thread to process the message. But, if your Stop method was invoked by something on the UI (i.e. a message) that means the message pump is blocked on WaitOne. Deadlock.

You could, possibly, fix this simply by switching out Invoke with BeginInvoke. But, you're still ultimately blocking the UI thread--keeping it, in most cases, from processing useful messages.

Your question does not go into detail into what you're trying to do, so it's basically impossible to tell you exactly, or with any certainty, what to do to solve your problem. Short answer: redesign so you don't have to wait. If you're still stuck on that, I'd suggest asking a different question outlining what you want to accomplish, what you've tried, and what to do to do it better.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98