5

I have been looking around for over a week now, and I haven't been able to find anyone else having a similar problem to what I'm seeing here.

I'm working with an OLD application running on Windows XP and developed in Visual Studio 2003. All of a sudden about 3 weeks ago, the application becomes unresponsive and the operator has to do the Windows three-finger-salute (CTRL-ALT-DEL) to bring up the task manager, kill the application process (which is shown as Not Responding) and restart the application.

I managed to have it happen once in the debugger, and when I paused the application it was waiting the system to return from attempting to set the System.Windows.Forms.Timer.Interval property.

Here's the object and where it appeared to hang, this isn't how it's written in the source code

internal static System.Windows.Forms.Timer timerMtimeOut;

// This is in an initialization method.
timerMtimeOut = new System.Windows.Forms.Timer();   
timerMtimeOut.Tick += new System.EventHandler(timerMtimeOut_Tick);

// this is how it's value is set.
timerMtimeOut.Interval = 1 * msec;  // <-- This is where it was in the debugger
timerMtimeOut.Enabled = true;


private static void timerMtimeOut_Tick(object sender, System.EventArgs e)
{           
    mTimeOut +=timerMtimeOut.Interval/msec;
}

The application essentially becomes unresponsive and has to be shut down using the Task Manager and restarted.

It's been working fine for years and then this just started happening about 2-3 weeks ago.

Has anyone else seen this behavior?

fmarcelino
  • 63
  • 4
  • most problems like this are truly coding related, why don't you show the code that you suspect is hanging. – T McKeown Aug 04 '14 at 20:21
  • how many threads are creating... how many times are calling/creating a timer? – T McKeown Aug 04 '14 at 20:23
  • I've added the code for the particular Timer object. It's a single thread, but the timer is enabled and disabled multiple times. This code has pretty much been untouched since it was originally written (before my time). What I did do was remove the timerMtimeOut.Start() and Stop() calls after the respective timerMtimeOut.Enable = true and false. – fmarcelino Aug 04 '14 at 20:31
  • It might be worth mentioning that we have two machines that are running this source code and the application hasn't become un-responsive on the second machine. – fmarcelino Aug 04 '14 at 20:33
  • I suppose you've already though about the fact that you might be chasing a wild goose. Just because you saw something happen on your machine and that's where the code broke doesn't necessarily mean that's what's happening on the other. In any case, is it possible to completely disable the timer and see if the problem goes away on that other machine, and know for sure it's related to this? Your comment indicates you may have already done this but it isn't clear. – Steve Aug 04 '14 at 21:52
  • I did. What I ended up doing is removing the timer and just replace it with using a DateTime object and checking if a second has passed, and the issue moved to a different location but it hasn't seem to freeze the application there any longer. – fmarcelino Aug 05 '14 at 12:57
  • "It's been running fine for years and then this just started happening." Really? There were no code changes just prior to it starting to misbehave? That strains credibility. You're *certain* nothing changed in the code? – Jim Mischel Nov 17 '14 at 00:37

1 Answers1

1

The most likely cause is that you are using the timer in a way it was not built for. The first line of code gives a hint:

internal static System.Windows.Forms.Timer timerMtimeOut;

There is no good reason to declare a System.Windows.Forms.Timer static, because this specific timer is designed to be linked to a specific Window (Form instance), and will cause the tick events to be fired in that form's main thread. It does so by sending messages into the threads message queue when the timer hits a tick. The message is then processed in the forms thread (WndProc) together with all other messages such as mouse movement and keyboard input.

If you instantiate multiple windows which access the timer, then problems will turn up sooner or later.

When the OS says that a process is not responding, it detects this by looking at how messages in the main threads message queue are being processed. If they are not being processed, then either the main thread is running a lengthy routine, or has got into some infinite loop. Calling Thread.Sleep() (as stated in your questions title) from the main thread will cause message processing to pause (and will prevent the ticks to be processed during the sleep).

Lengthy procedures should be run in a separate thread in order to keep an application responsive. You probably would like to show a progress bar and also give the user the opportunity to abort the process. This is hard to do if you run the lengthy process in the main thread. There is a dirty workaround by calling Application.DoEvents() somewhere in the loop, which will process the message queue on the fly. But you should be extremely careful to disable UI buttons when using this workaround, or else your user might start the process multiple times (recursively) or change some other state on which your process depends.

A little off topic, but the name of the variable suggests you are trying to count the number of intervals during a lengthy process? Note that if that lengthy process is running in the Form's main thread, the timer's tick events will queue up in the message loop and will only be executed after the lengthy process has finished its work and message processing is resumed. The approach you mention in the comments with a DateTime field is allot simpler, safer and better than using a timer.

When you need a timer that will execute code immediately when the tick is hit, you could use a System.Threading.Timer instead of the System.Windows.Forms.Timer. If you need to control it from multiple threads, use a System.Timers.Timer instead (that one is thread safe). Note that these timers will execute their event's in different threads. Also note that you should never manipulate controls or form's from other threads than the forms main thread. An easy way to do so is built into the framework with the Control.Invoke() method, which in turn will use the message loop to queue the operation.

Louis Somers
  • 2,560
  • 3
  • 27
  • 57