Search code examples
c#multithreadingtimer

System.Timers.Timer - How to change timer intervals on the fly?


I'm making a service. Among other things, it must read the value from registry and configure "Primary" timers' interval according to this value. Now it should do it not only in constructor phase, but also be able to change this interval when it has been changed in registry. How do I do that?

In other words, I have a code like this:

using System.Timers;

public static class GVARS
{
        public static Config valFromRegistry = new ConfigRegistry().Result;
}

class Program
{
    static void Main(string[] args)
    {
        int timerPeriod = (int)(uint)GVARS.valFromRegistry.Interval * 60000;

        Timer primaryTimer = new Timer(timerPeriod);
        primaryTimer.Interval = timerPeriod;
        primaryTimer.Elapsed += RunPrimaryPayload;
        primaryTimer.Start();
                
       
        Console.ReadLine();
    }

    private static void RunPrimaryPayload(object sender, ElapsedEventArgs eventArgs)
    {
        SomeClass.SomeMethod(someArgs);
        GVARS.valFromRegistry.Interval = (int)someNewValue;
    }
}

Somewhere down the code I might change valFromRegistry.Interval and I want primaryTimer to respond to those changes. How do I get there?

PS. It's not really important to me how I'm gonna check for changes in registry, be it another timer or event. Whatever works.

PS2. I have a possible idea to use System.Threading.Timer for primaryTimer instead of System.Timers.Timer since the former has method Change() which I might call from another little configrationUpdateTimer every minute or so and make primaryTimer respond to configuration changes this way. Am I right?


Solution

  • Ok, I've managed to solve my problem by creating class with 2 Timers: one checking for config changes (master) and another (slave) is doing actual payload:

    public class UniversalTimer
    {
        public System.Threading.Timer MasterTimer;
        public System.Threading.Timer SlaveTimer;
        private int lastMainTimerInterval = 0;
    
        public UniversalTimer()
        {
            MasterTimer = new System.Threading.Timer(new System.Threading.TimerCallback(MasterTimerCallback), null, 0, 60000);
            SlaveTimer = new System.Threading.Timer(new System.Threading.TimerCallback(SlaveTimerCallback), null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        }
        
        private void MasterTimerCallback(object obj)
        {
            Log.Debug("[{0}:{1}:{2}] Re-reading configuration from registry", "Program", "UniversalTimer", "MasterTimerCallback");
            var currentSettings = new ConfigRegistry().Result;
    
            if ((int)currentSettings.Interval != lastMainTimerInterval)
            {
                Log.Debug("[{0}:{1}:{2}] Setting interval for Main Timer", "Program", "UniversalTimer", "SlaveTimerCallback");
                lastMainTimerInterval = (int)currentSettings.Interval;
                this.MainTimer.Change(0, (int)currentSettings.Interval * 60000);
            }
        }
    
        private void SlaveTimerCallback(object obj)
        {
            Log.Debug("[{0}:{1}:{2}] Executing main cycle", "Program", "UniversalTimer", "SlaveTimerCallback");
        }
    
        public void Dispose()
        {
            MasterTimer.Dispose();
            SlaveTimer.Dispose();
        }
    }