3

I'm using a System.Threading.Timer in my windows service for nightly import routines. It looks every minute into the database for new files to be imported. Now, since the service runs all day long, i want to change it so that it runs at night every minute and at day every 5th minute.

Therefore i thought i could check the current time, between 7am and 10PM use the day-interval-configuration value, otherwise the night-interval.

Now to the actual question: why is there no property in the Timer-class which indicates the current period/interval? Then i could decide whether i have to change it or not according to it's value.

As a workaround i could store it in an additonal field, but i wonder if it's possible to get the value from the timer itself.

Note that i'm using this constructor:

//start immediately, interval is in TimeSpan, default is every minute
importTimer = new System.Threading.Timer(
    ImportTimer_Elapsed,
    null,
    TimeSpan.Zero,
    Settings.Default.ServiceInterval_Night
);
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • If that timer doesn't suit your needs then use one of the other timers in .NET that has a more robust feature set. – Servy Jun 02 '15 at 12:59
  • 2
    The "why" ought to be obvious, Microsoft did not write them. That's a threading race that can't happen, feature not a bug. Nothing you can't fix yourself with a variable. And a lock. – Hans Passant Jun 02 '15 at 13:00
  • Do you need to get the interval or would it suffice to be setable? In that case `Change()` should work. – Patrik Jun 02 '15 at 13:03
  • @HansPassant: threading race is a good reason, thanks. – Tim Schmelter Jun 02 '15 at 13:06
  • @PatrikEckebrecht: i want to know whether or not it is necessary to change the timer (or to recreate it via constructor). Thats why i'm looking for a property. But as i've mentioned already, i could use another field. I just haven't seen such a class before which doesn' t expose any properties even if it should have some. That's why i've wondered if it's a common design decision. – Tim Schmelter Jun 02 '15 at 13:14

3 Answers3

3

Why is there no property in the Timer-class which indicates the current period/interval?

I assume (I'm not part of the .NET implementation team, so have to assume) this is because it used a Win32 Waitable Timer. And there is no API to get the settings of a Waitable Timer.

Note, if such properties did exit there would be a race condition:

  • Thread 1 reads the property and starts some business logic based on it
  • Thread 2 changes the property (invalidating thread 1's logic)
  • Thread 1 updates the property.

while any specific use of a timer may not suffer this, the general case has to cater for it.

(In Win32 this is even worse a WaitableTimer can be named, and thus accessed from other processes.)

Richard
  • 106,783
  • 21
  • 203
  • 265
  • But is uses wrapper like the [`TimerQueueTimer`-class](http://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs,fd01ae537237d3f6) which actually stores the period among other properties. So it should be possible to provide it but it appears to be undesirable.. – Tim Schmelter Jun 02 '15 at 13:23
  • Without looking at something like Rotor, I do not know if the implementation has changed (eg. each instance used its own Win32 timer to the current implementation). In any case the race conditions associated with reading the settings make not having the properties exposed a good choice. Your code just needs to track `dayRate` flag with logic in the handler `if dayTime and not dayRate then switch rate…`. – Richard Jun 02 '15 at 13:56
  • if you'd mention the possible race condition i could mark your answer as accepted since it seems to be the reason for hiding it. I have already implemented the workaround with another field successfully. I was just curious why that is so. Thanks. – Tim Schmelter Jun 02 '15 at 14:32
  • @TimSchmelter done. Of course there are others where threads assume their change has been applied when another thread has made a different change… Small applications are unlikely to see these issues, a large application built by multiple teams around a core timer driving operations has much greater potential for issues. – Richard Jun 02 '15 at 17:19
0

You can use System.Timers.Timer instead, which provides such a property (".Intervall")

System.Threading.Timer does not have an internal field with the intervall value. I took a look into the .net code and i saw it isnt possible to get the current period by reflection.

Cadburry
  • 1,844
  • 10
  • 21
  • Thanks but: [Why doesn't Windows Service work properly with System.Timers.Timer or System.Windows.Forms.Timer](http://stackoverflow.com/questions/9208378/why-doesnt-windows-service-work-properly-with-system-timers-timer-or-system-win) – Tim Schmelter Jun 02 '15 at 13:07
  • @TimSchmelter HI - I know - but this only meets a System.Windows.Forms.Timer: not the System.Timers.Timer https://support.microsoft.com/kb/820639 --> "...To resolve this issue, use server timers from the System.Timers namespace instead of Windows Forms timers from the System.Windows.Forms namespace. To do this, follow these steps..." – Cadburry Jun 02 '15 at 13:11
0

Don't mess around with the tick rate. Instead invoke your code after a fixed number of ticks, depending on time:

private void ImportTimer_Elapsed(object o)
{
    tickCount--;
    if (tickCount <= 0)
    {
        // do your stuff

        tickCount = Between7AMAnd10PM() ? 5 : 1;
    }
}
David Arno
  • 42,717
  • 16
  • 86
  • 131
  • I don't want to (re-)create the timer in `Elapsed` event if not necessary. The code i've shown is the initial initialization but it should only change if necessary. Also, the timer itself elapsed, so no need to count. – Tim Schmelter Jun 02 '15 at 13:10