Timer randomly doesn't fire

473 Views Asked by At

I have code that looks like this

mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, Timeout.Infinite);

Stopwatch tmStopwatch = new Stopwatch();

private void SomeTimerCallback(object state)
{
    // doing minimal work here

    Console.WriteLine("{0}: SomeTimerCallback time: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, tmStopwatch.ElapsedMilliseconds);
    tmStopwatch.Restart();

    // Better to be on the safe side and do this slightly more than once per second, than slightly less.
    mTestModeMetadataTimer.Change(990, Timeout.Infinite);
}

Everything works fine except that occasionally there's a huge delay between timer events as seen in this console output.

 31: SomeTimerCallback time: 998
 21: SomeTimerCallback time: 997
 20: SomeTimerCallback time: 999
 3: SomeTimerCallback time: 989
 3: SomeTimerCallback time: 1000
 3: SomeTimerCallback time: 994
 37: SomeTimerCallback time: 999
 3: SomeTimerCallback time: 991
 29: SomeTimerCallback time: 1002
 37: SomeTimerCallback time: 1000
 3: SomeTimerCallback time: 17568
 3: SomeTimerCallback time: 999
 29: SomeTimerCallback time: 993

This is a small portion of a pretty sizable application. The same behavior existed with a System.Timers.Timer and, in fact, occurs for various other times throughout the application. I added the thread ID to the console output of this particular timer to hopefully gain a little more insight as to why there's a random 17.5 second elapsed time among the correct one second events.

Is there something I'm obviously doing wrong? Perhaps there's some more data I can gather to figure out why my timers are acting funny?

Any suggestions here would be greatly appreciated.

3

There are 3 best solutions below

4
On

From your comment the reason this happens is you are exhausting the threads in the thread pool. Because every thread was in use the timer had to wait 17.5 seconds for a thread to become available before it could run.

Your options as I see it are either increase the max number of threads in the thread pool or use a different timer that does not use the thread pool (System.Timers.Timer with a synchronization object that does not use the thread pool(Still uses the thread pool to kick it off) or a System.Windows.Forms.Timer with a message pump running)

0
On

System.Threading.Timer invokes an event handler on a worker thread obtained from the CLR thread pool. If the thread pool is in starvation, it may happen that the callback is queued until the thread is freed.

To check if you are exhausting the thread pool, you can log the number of available threads periodically while debugging:

int workerThreads;
int completitionPortThreads;
System.Threading.ThreadPool.GetAvailableThreads(out workerThreads, out completitionPortThreads);
1
On

Try with the periodic in the Timer constructor :

mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, TimeSpan.FromMilliseconds(990));

Are you sure you weren't in debug mode and you let the time go before continue ?