Search code examples
c#multithreadingtimerthread-sleep

.NET Timers, do they fire at the exact interval or after processing + interval


So a simple enough question really.

How exactly does the interval for System.Timers work?

Does it fire 1 second, each second, regardless of how long the timeout event takes or does it require the routine to finish first and then restarts the interval?

So either:

  1. 1 sec....1 sec....1 sec and so on
  2. 1 sec + process time....1 sec + process time....1 sec + process time and so on

The reason I ask this is I know my "processing" takes much less than 1 second but I would like to fire it every one second on the dot (or as close as).

I had been using a Thread.Sleep method like so:

Thread.Sleep(1000 - ((int)(DateTime.Now.Subtract(start).TotalMilliseconds) >= 1000 ? 0 : (int)(DateTime.Now.Subtract(start).TotalMilliseconds)));

Where start time is registered at start of the routine. The problem here is that Thread.Sleep only works in milliseconds. So my routine could restart at 1000ms or a fraction over like 1000.0234ms, which can happen as one of my routines takes 0ms according to "TimeSpan" but obviously it has used ticks/nanoseconds - which would then mean the timing is off and is no longer every second. If I could sleep by ticks or nanoseconds it would be bang on.

If number 1 applies to System.Timers then I guess I'm sorted. If not I need some way to "sleep" the thread to a higher resolution of time i.e ticks/nanoseconds.

You might ask why I do an inline IF statement, well sometimes the processing can go above 1000ms so we need to make sure we don't create a minus figure. Also, by the time we determine this, the ending time has changed slightly - not by much, but, it could make the thread delay slightly longer causing the entire subsequent sleeping off.

I know, I know, the time would be negligible... but what happens if the system suddenly stalled for a few ms... it would protect against that in this case.

Update 1

Ok. So I didn't realise you can put a TimeSpan in as the timing value. So I used the below code:

Thread.Sleep(TimeSpan.FromMilliseconds(1000) - ((DateTime.Now.Subtract(start).TotalMilliseconds >= 1000) ? TimeSpan.FromMilliseconds(0) : DateTime.Now.Subtract(start)));

If I am right, this should then allow me to repeat the thread at exactly 1 second - or as close as the system will allow.


Solution

  • IF you have set AutoReset = true; then your theory 1 is true, otherwise you would have to deal with it in code – see the docuementation for Timer on MSDN.