Advanced   Java   Services Threads beenden Back Next Up Home


Obsolete: Resume(), Suspend(), u.a.

Wie in Javca gibt es auch in C# in der Klasse Thread Methoden und Properties, die nicht mehr verwendet werden sollen, da sie nicht korrekt arbeiten. Außer den oben erwähnten Methoden findet man noch weitere in der API unter msdn.microsoft.com/en-us/library/system.threading.thread.aspx.


Threads beenden mit break

Thread die quasi endlos laufen sind nichts unübliches. Hier kann man eine Bedingung einbauen und prüfen, ob man die Schleife verlassen soll. Das wird mit dem folgenden Beispiel demonstriert.

class MyThread
{
   private bool running = true;
   private Thread th;

   public MyThread()
   {
      this.th = new Thread(Run);
      this.th.Start();
   }

   public void Run()
   {
      int i=0;
      while(running)
      {
         Console.WriteLine("runnin' " + ++i);
         // some work...
      }
      Console.WriteLine("end Run");
   }

   public void stopThread()
   {
      running = false;
   }
}

Ein Mainprogramm startet den Thread und beendet ihn nach ca. 0,1 Millisekunde. Mit Hilfe der Struktur TimeSpan lassen sich kleinere Zeiteinheiten realisieren. Die Kleinste Einheit ist 1 tick, was ca. 100 Nanosekunden entspricht, dementsprechend sind 1000 ticks etwa 0,1 Sekunden.

public class Main
{
   public static void Main(String[] args)
   {
      TimeSpan ts = new TimeSpan(1000);   // 1 tick = 100 nanoseconds, 10 000 ticks = 1 millisecond
      MyThread mt = new MyThread();   // Thread startet sofort
      Thread.Sleep(ts);   // 0,1 milliseconds
      mt.stopThread();
   }
}

Bei dieser Variante wird der Thread immer nach einem vollendeten Schleifendurchlauf beendet. Drei Screenshots zeigen das deutlich unterschiedliche Verhalten.

csharp-threads-21.jpg

csharp-threads-22.jpg

csharp-threads-23.jpg


Threads beenden mit Interrupt()

Die Methode Interrupt() aus der Klasse Thread bietet eine weitere Möglichkeit einen Thread zu beenden.


Interrupt() selbst beendet keinen Thread

Wie der Name schon sugeriert, unterbricht diese Methode den laufenden Thread lediglich, indem sie eine ThreadInterruptedException auslöst. Im catch-Zweig kann dann entschieden werden, ob man den Thread tatsächlich beenden will. Eine ThreadInterruptedException wird aber nur dann ausgelöst, wenn der Thread sich im Zustand WaitSleepJoin befindet.


Reagieren auf eine Interruptanforderung

Die Methode TestInterrupt() beendet bei der dritten Interruptanforderung die Endlosschleife mit einem break.

public static void TestInterrupt()
{
   for (int i = 1; ; i++)
   {
      try
      {
         Console.WriteLine("Thread going to sleep.");
         Thread.Sleep(Timeout.Infinite);
      }
      catch (ThreadInterruptedException ex)
      {
         Console.WriteLine("sleep interrupted by another thread " + i);
         if (i == 3) break;
      }
   }
   Console.WriteLine("end thread");
}

Main kann z. Bsp. so aussehen.

private static void Main(string[] args)
{
   Thread th = new Thread(TestInterrupt);
   th.Start();
   Thread.Sleep(1000);  // 1 second
   th.Interrupt();
   Thread.Sleep(1000);  // 1 second
   th.Interrupt();
   Thread.Sleep(1000);  // 1 second
   th.Interrupt();
   Thread.Sleep(2000);
   th.Interrupt();
   // Interrupt auf einen bereits beendeten Thread löst keine Exception aus.
}

Die Konsolausgabe.

csharp-threads-24.jpg


Nichunterbrechbares Warten mit SpinWait()

Ein nichtunterbrechbares Warten kann man mit der Methode SpinWait() erreichen. Diese Methode arbeitet mit einer Schleife ohne Statements, die nach einer Anzahl von Wiederholungen beendet wird. Die Anzahl wird der Methode als Parameter übergeben. Die folgende Methode TestSpinWait() beendet sich nach 100 Millionen Durchläufen und ignoriert Interruptanforderungen.

public static void TestSpinWait()
{
   try
   {
      Console.WriteLine("Thread going to spinwait.");
      Thread.SpinWait(1000000000);
      Console.WriteLine("end spinwait");
   }
   catch (ThreadInterruptedException ex)
   {
      Console.WriteLine("interrupted by another thread");
   }
}

Main

private static void Main(string[] args)
{
   Thread th = new Thread(TestSpinWait);
   th.Start();
   Thread.Sleep(10);  // 10 millisecond
   th.Interrupt();
   Console.WriteLine("end main");

Die Meldung aus dem catch()-Zweig wird nicht ausgegeben.

csharp-threads-25.jpg


Nichunterbrechbares Warten ohne SpinWait()

Es geht auch ohne SpinWait(). Die folgende rechenintensive (aber nutzlose) Schleife ist nicht mit Interrupt() unterbrechbar, es sei denn man fügt ein Thread.Sleep() ein, wobei ein tick (100 Nanosekunden) schon ausreicht.

public static void InterruptTest()
{
   TimeSpan ts = new TimeSpan(1);  // 100 nanosek
   for(int j = 1 ; ; j++)
   {
      try
      {
         Console.WriteLine("runnin' " + j);
         long sum = 0;
         for(long i=1; i<100000; i++)
         {
            sum += i*i*i*i*i/i/i/i/i;
         }
         Thread.Sleep(ts);  // (*)
      }
      catch(ThreadInterruptedException ex)
      {
         Console.WriteLine("interrupted by another thread");
         break;
      }
   } // end for
   Console.WriteLine("end Run");
}

Das zugehörige Main versucht nach 100 Millisekunden eine Unterbrechung.

private static void Main(string[] args)
{
   Thread th = new Thread(InterruptTest);
   th.Start();
   Thread.Sleep(100);  // 100 millisecond
   th.Interrupt();
   Console.WriteLine("end main");
}

Falls in der Methode InterruptTest() das mit (*) gekennzeichnete Statement Thread.Sleep(1) nicht auskommentiert ist sieht die Konsolausgabe so aus, ...

csharp-threads-26.jpg

und falls man es auskommentiert (und dann nach etwa fünf Sekunden den Screenshot macht), dann so.

csharp-threads-27.jpg












Valid XHTML 1.0 Strict top Back Next Up Home