Advanced   Java   Services Timer Back Next Up Home


Timer

Mit der Klasse Timer in System.Threading läßt sich Programmcode zu einem späteren Zeitpunkt und/oder auch in periodischen Abständen abarbeiten. Dazu besitzt die Klasse Timer verschiedene Konstruktoren, die alle eine Instanz vom Typ TimerCallback erhalten. TimerCallBack ist ein Delegate in System.Threading und steht für Funktionen, die einen Parameter vom Typ Object erhalten und nichts zurückgeben. Die weiteren Parameter im Konstruktor können vom Typ int oder von der Struktur TimeSpan sein. Mit Hilfe der Methode change() von Timer kann man Parameter nach der Objekterzeugung ändern.

Einige Beispiele.


Beispiel 1: Single Shot with Delay
/*
   SingleShotWithDelay
*/
private static void Main()
{
   Console.WriteLine("start main: " + DateTime.Now);
   int delay = 2000; // Millisekunden
   int period = -1; // oder 0
   TimerCallback tcb = new TimerCallback( (ob) => Console.WriteLine("timer: " + DateTime.Now) );
   Timer t = new Timer(tcb, null, delay, period);
   Thread.Sleep(5000);
   Console.WriteLine("end main");
}

Screenshot

csharp-threads-52.jpg


Beispiel 2: Periodic Shot with Delay

Hier erkennt man, daß ein periodischer Timer ein Dämonthread ist. Er läuft periodisch weiter solange Main oder ein anderer Vordergrundthread noch läuft. Erst wenn der letzte Vordergrundthread beendet ist, wird der Timer beendet.

/*
   PeriodicShotWithDelay
   Periodic Shot: Timer ist ein Daemon, sobald Main endet, wird er gekillt.
*/
private static void Main()
{
   Console.WriteLine("start main: " + DateTime.Now);
   int delay = 2000;
   int period = 1000; //
   TimerCallback tcb = new TimerCallback((ob) => Console.WriteLine("timer: " + DateTime.Now));
   Timer t = new Timer(tcb, null, delay, period);
   Thread.Sleep(5000);
   Console.WriteLine("end main");
}

Screenshot

csharp-threads-53.jpg


Beispiel 3: Selfterminating periodic Shot with Delay

Will man nur eine begrenzte Anzahl von Wiederholungen, so muß man den Timer mit der Methode dispose() beenden. Verwendet man den Defaultkonstruktor, so wird beim Aufruf der CallBackMethode die Timerinstanz übergeben. Die CallBackMethode muß aber außerdem noch wissen, wie oft sie aufgerufen werden soll und einen Zähler hochzählen um zu vergleichen. Diese Daten kann man übermitteln, wenn man die CallBackMethode in eine eigene Klasse legt.

class RepetitionCallBack
{
   private int repetitions = 0;
   private int count = 0;

   public RepetitionCallBack(int repetitions)
   {
      this.repetitions = repetitions;
   }

   public void TimerProc(object timer)
   {
      count++;
      Console.WriteLine("timer: " + DateTime.Now);
      if (this.count == this.repetitions)
      {
         // The state object is the Timer object !
         Timer t = (Timer)timer;
         t.Dispose();
         Console.WriteLine("timer disposed");
      }
   }
}

Eine Instanz dieser Klasse verwenden wir wie folgt.

/*
   Selfterminating Periodic Shot with Delay
*/
private static void SelfterminatingPeriodicShotWithDelay()
{
   Console.WriteLine("start main: " + DateTime.Now);
   int delay = 1000;
   int period = 1000; //
   int howOften = 7;
   RepetitionCallBack rcb = new RepetitionCallBack(howOften);
   TimerCallback tcb = new TimerCallback(rcb.TimerProc);
   Timer t = new Timer(tcb);  // durch diesen Konstruktor wird t an die CallBackMethode übergeben
   t.Change(delay, period);
   Thread.Sleep(9000);
   Console.WriteLine("end main");
}

Screenshot

csharp-threads-54.jpg

Es folgen dieselben drei Beispiele, aber nun mit der Struktur TimeSpan


Beispiel 4: Single Shot with Delay
/*
   SingleShotWithDelay
*/
private static void SingleShotWithTimeSpan()
{
   Console.WriteLine("start main: " + DateTime.Now);
   DateTime now = DateTime.Now;
   DateTime time2Start = now.AddSeconds(3);
   TimeSpan delay = time2Start - now;

   TimerCallback tcb = new TimerCallback( (ob) => Console.WriteLine("timer: " + DateTime.Now) );
   Timer t = new Timer(tcb, null, delay, TimeSpan.FromMilliseconds(-1)); // 0 oder -1 : Single Shot
   Thread.Sleep(5000);
   Console.WriteLine("end main");
}

Beispiel 5: Periodic Shot with Delay

/*
   PeriodicShotWithDelay
   Periodic Shot: Timer ist ein Daemon, sobald Main endet, wird er gekillt.
*/
private static void RepetitionTillMainEndsTimeSpan()
{
   Console.WriteLine("start main: " + DateTime.Now);
   DateTime now = DateTime.Now;
   DateTime time2Start = now.AddSeconds(2);
   TimeSpan startSpan = time2Start - now;

   //TimerCallback tcb = new TimerCallback(TimerProc2);
   TimerCallback tcb = new TimerCallback((o) => Console.WriteLine("timer: " + DateTime.Now));
   Timer t = new Timer(tcb);
   t.Change(startSpan, TimeSpan.FromSeconds(1));  // jede Sekunde
   Thread.Sleep(7000);
   Console.WriteLine("end main");
}

Beispiel 6: Selfterminating periodic Shot with Delay

Hier braucht man wieder eine passend aufgebaute Hilfsklasse

class RepetitionCallBack
{
   private DateTime time2End;

   public RepetitionCallBack2(DateTime time2End)
   {
      this.time2End = time2End;
   }

   public void TimerProc(object state)
   {
      Console.WriteLine("timer: " + DateTime.Now);
      if (time2End <= DateTime.Now)  // nicht gerade geschickt gemacht !
      {
         // The state object is the Timer object !
         Timer t = (Timer)state;
         t.Dispose();
         Console.WriteLine("timer disposed");
      }
   }
}

Und so wird sie verwendet.

private static void SelfterminatingPeriodicShotWithTimeSpan()
{
   Console.WriteLine("start main: " + DateTime.Now);
   DateTime now = DateTime.Now;
   DateTime time2Start = now.AddSeconds(2);
   TimeSpan startSpan = time2Start - now;
   DateTime time2End = now.AddSeconds(7);
   RepetitionCallBack2 rcb2 = new RepetitionCallBack2(time2End);
   TimerCallback tcb = new TimerCallback(rcb2.TimerProc);
   Timer t = new Timer(tcb);
   t.Change(startSpan, TimeSpan.FromSeconds(1));  // jede Sekunde
   Thread.Sleep(9000);
   Console.WriteLine("end main");
}
Valid XHTML 1.0 Strict top Back Next Up Home