private int interval = 3600000; private Timer timer = new Timer(2000); public void Start() { this.timer.Elapsed += this.OnTimerElapsed; this.timer.Start(); } private void OnTimerElapsed(object sender, ElapsedEventArgs e) { this.timer.Stop(); ..... this.timer.Interval = this.interval; this.timer.Start(); }
Drobným nedostatkem tohoto kódu je fakt, že kód vlastně neběží v nastaveném intervalu, ale tento interval je prodloužen i o vlastní běh metody - například pokud je interval nastaven na 10 sekund a metoda běží také 10 sekund, uplyne mezi dvěma voláními 20 sekund.
Takže tady je lepší řešeni- použije se System.Threading.Timer - ten umožňuje nastavit jak čas prvotního spuštění, tak interval mezi následnými voláními.
private Timer timer = null; private readonly TimerSemaphore semaphore = new TimerSemaphore(); public void Start() { int interval = 3600000; this.timer = new Timer(new TimerCallback(this.OnTimerElapsed), null, 200, interval); } private void OnTimerElapsed(object state) { if (this.semaphore.IsRunning) return; do { ... } while (this.semaphore.ShouldBeRunning); }
Objekt semaphore zabraňuje opětovnému spuštění metody, pokud tato již běží a navíc v případě, že dojde k tomuto opětovnému zavolání spustí metodu ihned znovu - takže pokud metoda běží pomaleji a doba běhu překročí nastavený interval, je metoda volána ihned znovu - na rozdíl od prvního kódu, kde se opětovně čeká.
Takto vypadá vlastní kód třídy TimerSemaphore:
public class TimerSemaphore { private bool isRunning = false; private bool shouldBeRunning = false; private bool isStopped = false; private object locker = new object(); public bool IsRunning { get { lock(this.locker) { if (this.isStopped) return false;
if(!this.isRunning) { this.isRunning = true; return false; } else { this.shouldBeRunning = true;
return true; } } } } public bool ShouldBeRunning { get { lock(this.locker) { if this.isStopped) return false; if(this.shouldBeRunning) { this.isRunning = true; this.shouldBeRunning = false; return true; } else { this.isRunning = false; return false; } } } } public void Stop() { lock(this.locker) { this.isRunning = false; this.shouldBeRunning = false; this.isStopped = true; } } }