SlideShare ist ein Scribd-Unternehmen logo
1 von 74
Threading




C# Workshop, TU Darmstadt 2008,
Präsentation von Qiong Wu (Microsoft Junior Student Partner)
   Prozesse / Threads?
   Arbeiten mit Threads
   Erstellen von Threads
   Threads beenden
   Datenzugriff mit Threads
   Deadlocks
   ThreadPools
   Asnychrone Programmierung
   Timer
   Windows Forms & Threading
   Ablaufende Programme
   Heißen unter Windows auch Tasks
   Erlauben einem Prozessor mehrere Aufgaben
    „gleichzeitig“ zu bearbeiten
   Interprozesskommunikation
   Besitzen
     Virtuellen Adressspeicher
     Ausführbaren Code
     Mindestens einen Ausführungsthread
   Teilbereiche eines Prozesses
   Erlauben einem Prozess mehrere Aufgaben
    „gleichzeitig“ zu bearbeiten.
   Teilen sich virtuellen Adressspeicher und die
    Systemressourcen des Prozesses zu dem sie
    gehören
   C# Programme starten automatisch
    Hauptthread
   Beides Konzepte zur parallelen
    Programmierung
   Prozesse sind unabhängige
    Ausführungseinheiten
   Threads als logische Arbeitsteile eines
    Prozesses
   Parallelisierung sowohl mit mehreren
    Prozessen als auch mehreren Threads
    theoretisch möglich
   Parallelisieren von Programmaufgaben
   Nutzen von Multi-Threaded Hardware
    (Multicore, Multiprozessor)
   Trennung von Benutzeroberfläche und
    Berechnung
   Verteilte Systeme
   Threads können die Performance
    beeinträchtigen (Thread Overhead)
   Threads sind häufige Fehlerquellen
   Viele Threads bedeuten auch viel Ärger
   Ergo: Threading nur dann einsetzen wenn es
    sinnvoll ist!
   Multithreading in C# relativ einfach
   Unterstützt asynchrones und synchrones
    Threading
   Wichtigstes Werkzeug: System.Threading
    Namespace
   Manuelles Erstellen von Threads
   Beenden von Threads
   Datenzugriffe koordinieren
   Asynchrone Programmierung
   ThreadPool verwenden
1.   Methode für Threadeinstiegspunkt erstellen
2.   ParametrizedThreadStart / ThreadStart
     Delegaten mit Verweis auf die
     Einstiegsmethode erstellen
3.   Thread Objekt mit Delegaten erstellen
4.   Optional: Threadeigenschaften festlegen
5.   Thread starten
   ThreadStart
     für parameterlose Threadmethoden
   ParametrizedThreadStart
     für Threadmethoden mit Parameter
     Parameter muss vom Typ object sein
Auszuführende
                                         Methode
static void Main(string[] args)
{
    ThreadStart TestThreadStart = new ThreadStart(ThreadMethod);
    Thread TestThread = new Thread(TestThreadStart);

   TestThread.Name = quot;Test Threadquot;;
   TestThread.Priority = ThreadPriority.Normal;
   TestThread.IsBackground = false;

   TestThread.Start();                      Threadoptionen

   Console.ReadLine();
}
                                        Kein Rückgabewert
static void ThreadMethod()
{
    Console.WriteLine(quot;Thread Runquot;);
}
Auszuführende
                                                            Methode
static void Main(string[] args)
{
    ParameterizedThreadStart TestThreadStart = new ParameterizedThreadStart(ThreadMethod);
    Thread TestThread = new Thread(TestThreadStart);

    TestThread.Name = quot;Test Threadquot;;
    TestThread.Priority = ThreadPriority.Normal;                    Threadoptionen
    TestThread.IsBackground = false;

    TestThread.Start(quot;Testquot;);
                                              Start mit Parameter
    Console.ReadLine();
}
                          Kein Rückgabewert                    object Parameter
static void ThreadMethod(object Parameter)
{
    Console.WriteLine(quot;Thread Run with Parameter: quot; + Parameter.ToString());
}
   Unterscheidung zwischen
     Foreground Threads
     Background Threads
   Thread.Join()
Thread ForegroundThread = new Thread(new ThreadStart(ThreadMethod));
ForegroundThread.Start();
                                                Foreground Thread
                                              Verhindert Beenden der
                                                    Applikation


Thread BackgroundThread = new Thread(new ThreadStart(ThreadMethod));
BackgroundThread.IsBackground = true;
BackgroundThread.Start();
                                                 Background Thread kann
                                                  nach Beendigung aller
                                                   Foreground Threads
                                                    terminiert werden
ThreadStart operation = new ThreadStart(ThreadMethod);
Thread[] theThreads = new Thread[5];
for (int x = 0; x <= 4; ++x)
{
    theThreads[x] = new Thread(operation);
    theThreads[x].Start();
}                                         Thread starten
foreach (Thread oneThread in theThreads)
{
    Console.WriteLine(quot;Waiting for Thread to terminatequot;);
    oneThread.Join();
    Console.WriteLine(quot;Thread terminatedquot;);
}

                                      Auf Threadende warten
   Bestimmt die Vorrangregelung bei der
    Ausführung eines Threads
   Thread.Priority Eigenschaft
   ThreadPriority Enum
       Lowest
       BelowNormal
       Normal
       AboveNormal
       Highest
Standardpriorität ist
                                               ThreadPriority.Normal


Thread NormalPriorityThread = new Thread(new ThreadStart(ThreadMethod));

Thread HighPriorityThread = new Thread(new ThreadStart(ThreadMethod));
HighPriorityThread.Priority = ThreadPriority.Highest;

NormalPriorityThread.Start();
HighPriorityThread.Start();

                                                 Setzen der Threadpriorität
                                                 auf ThreadPriority.Highest
   Thread.Abort()
     Löst ThreadAbortException aus
     Beendet Thread nach Auslösen der Exception
   Sicheres Beenden von Threads
     ThreadAbortException behandeln
   Alternative: Abortvariable
static void Main(string[] args)
{
    Thread newThread = new Thread(new ThreadStart(ThreadMethod));
    newThread.Start();
    Thread.Sleep(1000);
    newThread.Abort();
    Console.ReadLine();
}
                                       Thread beenden
static void ThreadMethod()
{
    try
    {
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine(quot;Thread - working.quot;);
            Thread.Sleep(100);
        }
    }
                                                     ThreadAbortException
    catch (ThreadAbortException e)                         behandeln
    {
        Console.WriteLine(quot;Thread - caught ThreadAbortException - resetting.quot;);
        Console.WriteLine(quot;Exception message: {0}quot;, e.Message);
    }
    finally
    {
        Console.WriteLine(quot;Just one more message before I dropquot;);
    }
}
   Einige Programmieren raten von
    Thread.Abort ab
   Gründe
     Thread.Abort kann Thread an jeder Stelle
      abbrechen
     Finally Statements können übergangen werden
     Ressourcen können ungeschlossen bleiben
   Ansatz: Abortvariable einführen und im
    Thread pollen
static void TestManualAbort()
{
    Thread newThread = new Thread(new ThreadStart(ManualAbortThreadMethod));
    newThread.Start();
    Thread.Sleep(1000);
    Abort = true;
}
static volatile bool Abort = false;
static void ManualAbortThreadMethod()
{
    while (true)
    {
        if (Abort == false)
        {
            Console.WriteLine(System.DateTime.Now.ToString());
        }
        else
        {
            break;
        }
    }
}
   Probleme mit Thread.Abort() lassen sich auch
    ohne Abortvariable umgehen
   Alternative Lösungen
     Code auf ThreadAbortException anpassen
     Constrained Execution Regions einsetzen
     (Fortgeschritten)
Oder einfach Pause?
   Vor Multithreading: Nur ein gleichzeitiger
    Zugriff auf Daten
   Mit Multithreading: Möglichkeit des
    gleichzeitigen Zugriffs auf Daten von
    mehreren Threads
   Was passiert wenn mehrere Threads
    gleichzeitig einen Datenbestand
    manipulieren?
   Mehrere Threads können eine gemeinsame
    Variable manipulieren
   Probleme beim Rückschreiben von Werten
   Fehlerhafte Werte als Ergebnis
Thread 1                                     Thread 2
X = X + 30                                   X = X + 15




     Variable einlesen         Variable einlesen
                         X=0
Thread 1         Thread 2
  X=0              X=0




           X=0
Thread 1         Thread 2
 X=30              X=0




           X=0
Thread 1                       Thread 2
 X=30                           X=15




    Variable schreiben
                         X=0
Thread 1                          Thread 2
Beenden…                            X=15




                     Variable schreiben
            X = 30
Thread 2
         Beenden…




X = 15
X = 15
   Interlocked Klasse
   Synchronisierungssperren
   Bietet atomare Operationen für Variablen
   Nur für triviale Operationen an einer Variable
    (Addieren, Dekrementieren, Vertauschen,
    Inkrementieren)
   Effektiv, aber beschränktes Einsatzgebiet
   Monitor.Enter() + Monitor.Exit()
   Lock Schlüsselwort
   ReaderWriterLock
   Mutex / Semaphore / AutoResetEvent /
    ManualResetEvent
   Setzt in Codeabschnitt eine
    Synchronisierungssperre
   Synchronisieren auf ein Objekt
     Besitzer des Monitor des Objekts erhält
      exklusiven Zugriff auf Codeabschnitt
     Andere blockieren bis Freigabe des Monitors
   Synchronisierungsobjekt als Parameter
   Umschließt Codebereich implizit mit
    Monitor.Enter() und Monitor.Exit()
Sperrvariable


public static object Lockvar = new object();
public static void LockMethod(object Parameter)
{
    Monitor.Enter(Lockvar);
    try
    {                                      Anfang
        count++;                    Synchronisierungssperre
        Console.WriteLine(quot;Thread quot; + count + quot; Writingquot;);
    finally
    {
        Monitor.Exit(Lockvar);
    }
}                                                 Ende
                                        Synchronisierungssperre
Sperrvariable


public static object Lockvar = new object();
public static void LockMethod(object Parameter)
{
    lock (Lockvar)                   Sperrvariable
    {
        count++;
        Console.WriteLine(quot;Thread quot; + count + quot; Writingquot;);
    }
}
   Zwei Threads schließen sich gegenseitig
    durch Synchronisationssperren aus
   Thread A wartet auf Thread B, Thread B
    wartet auf Thread A
   Endloses Warten
public static object Lockvar1 = new object();
                  public static object Lockvar2 = new object();
                  public static void DeadLockMethodOne()
                  {
                      lock (Lockvar1)
                      {                                      Sperrvariable
                          lock (Lockvar2)
Sperrt Lockvar1           {
                              Console.WriteLine(quot;Firstquot;);
                          }
                      }
                  }
                  public static void DeadLockMethodTwo()
                  {
                      lock (Lockvar2)
                      {
                          lock (Lockvar1)
Sperrt Lockvar2           {
                              Console.WriteLine(quot;Secondquot;);
                          }
                      }
                  }
   Sorgfältig Programmieren!
   Monitor.TryEnter() mit Zeitlimit
   Kurze Codeabschnitte sperren
   ReaderWriteLock Klasse ermöglicht
     Ausschließliche Lesesperre
     Schreibsperre
     Wechsel von Lese zu Schreibsperre und vice versa
Oder noch eine Pause?
   Erstellung eigener Threads oft unnötig
   ThreadPool verwaltet Threads die auf Abruf
    bereit stehen, Standardanzahl 25
   Overhead bei Threaderstellung und
    Threadvernichtung eliminiert
   ThreadPool Threads sind Hintergrundthreads
   ThreadPool Arbeitsaufgaben können nicht
    durch Fremdeinwirkung abgebrochen werden
   ThreadPool.QueueUserWorkItem
     Übergabe von Verweis auf Funktion
     Optional: Übergabe von Parameter
   ThreadPool.GetMaxThreads
     Anzahl der maximal verfügbaren Threads abrufen
   ThreadPool.SetMaxThreads
     Anzahl der maximal verfügbaren Threads
     festlegen
WaitCallback Delegate
                                                    Thread mit Parameter starten


WaitCallback workItem = new WaitCallback(ThreadMethod);

if (!ThreadPool.QueueUserWorkItem(workItem, quot;ThreadPooledquot;))
{
    Console.WriteLine(quot;Element konnte nicht in Warteschlange gestellt werdenquot;);
}
   Idee: Asynchrones Starten & Beenden eines
    Ablaufs
   Vorteile
     Keine manuelle Verwaltung des Threads notwendig
     Automatische Threadskalierung
     Performancegewinn durch automatische Nutzung
        von ThreadPool
   3 Verwendungsmodelle
        Warten-bis-fertig Modell
        Pollingmodell
        Rückrufmodell
   Asynchrone Operation starten
   Andere Arbeiten erledigen
   Mit EndXXX auf Ende der Operation warten
Andere Arbeiten ausführen


Console.WriteLine(quot;Start Async Fetchin..quot;);
GenericMethodDelegate<int> method = IntFetcher.Fetch;
IAsyncResult ar = method.BeginInvoke(null, method);
                                      Methode asynchron
Thread.Sleep(1000);                       ausführen
Console.WriteLine(quot;Got quot; + method.EndInvoke(ar));
Console.WriteLine(quot;End Async Fetchin..quot;);

                               Auf Ende der Methode
                                      warten
   Starten der asnychronen Operation
   Regelmäßig überprüfen ob die Operation
    abgeschlossen ist
   Nach Abgeschlossener Operation EndXXX
    aufrufen
Andere Arbeiten ausführen

Console.WriteLine(quot;Start Async Fetchin..quot;);
IAsyncResult ar2 = method.BeginInvoke(null, method);
                                         Methode asynchron
while (!ar2.IsCompleted)
                                             ausführen
{
    Thread.Sleep(1000);
}                                 Regelmäßig pollen

Console.WriteLine(quot;Got quot; + method.EndInvoke(ar2));
Console.WriteLine(quot;End Async Fetchin..quot;);


                                  Ergebnis abrufen (keine
                                       Wartezeit)
   Starten der asynchronen Operation mit
    Übergabe einer Rückruffunktion
Andere Arbeiten ausführen                      Callback Funktion angeben

Console.WriteLine(quot;Start Async Fetchin..quot;);
IAsyncResult ar3 = method.BeginInvoke(new AsyncCallback(CompleteFetch), method);

Thread.Sleep(1000);

static void CompleteFetch(IAsyncResult result)
{
    GenericMethodDelegate<int> method = (GenericMethodDelegate<int>)result.AsyncState;
    int i = method.EndInvoke(result);
    Console.WriteLine(quot;Got quot; + i);
    Console.WriteLine(quot;End Async Fetchin...quot;);
}


                                                          Ergebnis abrufen (keine
                                                               Wartezeit)
   Try Catch bei Aufruf der EndXXX Methode
    anwenden
     try
     {
           Console.WriteLine(quot;Got quot; + method.EndInvoke(ar2));
     }
     catch
     {
         Console.WriteLine(quot;Error occuredquot;);
     }
     finally
     {
         Console.WriteLine(quot;End Async Fetchin..quot;);
     }
   Delegaten erstellen
   BeginInvoke des Delegaten aufrufen
   EndInvoke des Delegaten aufrufen
Delegat auf auszuführende
        Methode

   public delegate TOutput GenericMethodDelegate<TOutput>();
                                 Methode dem Delegat
   static void TestAsync()
                                      zuweisen
   {
       Console.WriteLine(quot;Start Async Fetchin..quot;);
       GenericMethodDelegate<int> method = IntFetcher.Fetch;
       IAsyncResult ar = method.BeginInvoke(null, method);
       Thread.Sleep(1000);
       Console.WriteLine(quot;Got quot; + method.EndInvoke(ar));
       Console.WriteLine(quot;End Async Fetchin..quot;);
   }
                                       Blockieren bis asynchrone
      Methode asynchron starten
                                           Methode beendet
   Ruft eine Methode asynchron nach
    Zeitspanne auf
   Wiederholt Aufruf der Methode nach
    Zeitspanne
   Timer.Change
Tick Intervall

        TimerCallbackDelegate            Startverzögerung

static void TestTimer()
{
    Timer tm = new Timer(new TimerCallback(ThreadMethod), quot;Timerquot;, 0, 1000);
    Thread.Sleep(1000);
    tm.Change(0, 100);
}


                                                            Parameter
          Intervall / Verzögerung
                  ändern
   Häufigster Anwendungsfall für Threading:
    Rechenlast aus GUIs auslagern
   Dem Hauptthread möglichst wenig
    Rechenlast zuordnen
   Rechenlast in Hauptthread verursacht
    hängende GUIs
   Problematik: Zugriff auf Steuerelemente von
    Threads aus
private void cmdThreaded_Click(object sender, EventArgs e)
{
    Thread FormsThread = new Thread(new ThreadStart(DoWork));
    FormsThread.Start();
}

private void cmdUnthreaded_Click(object sender, EventArgs e)
{
    DoWork();
}
private void button1_Click(object sender, EventArgs e)
{
    Thread FormsThread = new Thread(new ThreadStart(ManipulateList));
    FormsThread.Start();
}

private void ManipulateList()
{
    listBox1.Items.Add(quot;testquot;);
}
   Direktes Manipulieren von Windows Forms
    Steuerelementen löst Exception aus
   Mit Invoke den UI Thread auffordern
    Manipulationen vorzunehmen
   Delegaten übergeben
   Asynchroner Aufruf ebenfalls möglich
   Optional: Eine Methode für Invoke und Direkt
    mit InvokeRequired Eigenschaft
Delegat nach Funktion
                                                    erstellen

private delegate void ManipulateListDelegate();

private void ManipulateList()
                                                     Invoke benötigt?
{
    if (listBox1.InvokeRequired == true)
    {
         listBox1.Invoke(new ManipulateListDelegate(ManipulateList));
    }
                                        Invoke aufrufen mit Verweis
    else
                                               auf Methode
    {
         listBox1.Items.Add(quot;testquot;);
    }
}                                             Manipulationen vornehmen
C# Workshop - Threading

Weitere ähnliche Inhalte

Mehr von Qiong Wu (13)

node.js workshop- node.js databases
node.js workshop- node.js databasesnode.js workshop- node.js databases
node.js workshop- node.js databases
 
node.js workshop- node.js unit testing
node.js workshop- node.js unit testingnode.js workshop- node.js unit testing
node.js workshop- node.js unit testing
 
node.js workshop- node.js middleware
node.js workshop- node.js middlewarenode.js workshop- node.js middleware
node.js workshop- node.js middleware
 
node.js workshop- node.js basics
node.js workshop- node.js basicsnode.js workshop- node.js basics
node.js workshop- node.js basics
 
node.js workshop- JavaScript Async
node.js workshop- JavaScript Asyncnode.js workshop- JavaScript Async
node.js workshop- JavaScript Async
 
node.js workshop- JavaScript Basics
node.js workshop- JavaScript Basicsnode.js workshop- JavaScript Basics
node.js workshop- JavaScript Basics
 
Parallele Softwareentwicklung mit .NET 4.0
Parallele Softwareentwicklung mit .NET 4.0Parallele Softwareentwicklung mit .NET 4.0
Parallele Softwareentwicklung mit .NET 4.0
 
S N A I L Final Presentation
S N A I L    Final  PresentationS N A I L    Final  Presentation
S N A I L Final Presentation
 
3 Interop Part2
3 Interop Part23 Interop Part2
3 Interop Part2
 
Kickoff
KickoffKickoff
Kickoff
 
2 Interop
2 Interop2 Interop
2 Interop
 
C# Workshop - Networking
C# Workshop - NetworkingC# Workshop - Networking
C# Workshop - Networking
 
Life In Power Point
Life In Power PointLife In Power Point
Life In Power Point
 

C# Workshop - Threading

  • 1. Threading C# Workshop, TU Darmstadt 2008, Präsentation von Qiong Wu (Microsoft Junior Student Partner)
  • 2.
  • 3. Prozesse / Threads?  Arbeiten mit Threads  Erstellen von Threads  Threads beenden  Datenzugriff mit Threads  Deadlocks  ThreadPools  Asnychrone Programmierung  Timer  Windows Forms & Threading
  • 4. Ablaufende Programme  Heißen unter Windows auch Tasks  Erlauben einem Prozessor mehrere Aufgaben „gleichzeitig“ zu bearbeiten  Interprozesskommunikation  Besitzen  Virtuellen Adressspeicher  Ausführbaren Code  Mindestens einen Ausführungsthread
  • 5.
  • 6. Teilbereiche eines Prozesses  Erlauben einem Prozess mehrere Aufgaben „gleichzeitig“ zu bearbeiten.  Teilen sich virtuellen Adressspeicher und die Systemressourcen des Prozesses zu dem sie gehören  C# Programme starten automatisch Hauptthread
  • 7. Beides Konzepte zur parallelen Programmierung  Prozesse sind unabhängige Ausführungseinheiten  Threads als logische Arbeitsteile eines Prozesses  Parallelisierung sowohl mit mehreren Prozessen als auch mehreren Threads theoretisch möglich
  • 8.
  • 9.
  • 10.
  • 11. Parallelisieren von Programmaufgaben  Nutzen von Multi-Threaded Hardware (Multicore, Multiprozessor)  Trennung von Benutzeroberfläche und Berechnung  Verteilte Systeme
  • 12. Threads können die Performance beeinträchtigen (Thread Overhead)  Threads sind häufige Fehlerquellen  Viele Threads bedeuten auch viel Ärger  Ergo: Threading nur dann einsetzen wenn es sinnvoll ist!
  • 13. Multithreading in C# relativ einfach  Unterstützt asynchrones und synchrones Threading  Wichtigstes Werkzeug: System.Threading Namespace
  • 14. Manuelles Erstellen von Threads  Beenden von Threads  Datenzugriffe koordinieren  Asynchrone Programmierung  ThreadPool verwenden
  • 15. 1. Methode für Threadeinstiegspunkt erstellen 2. ParametrizedThreadStart / ThreadStart Delegaten mit Verweis auf die Einstiegsmethode erstellen 3. Thread Objekt mit Delegaten erstellen 4. Optional: Threadeigenschaften festlegen 5. Thread starten
  • 16. ThreadStart  für parameterlose Threadmethoden  ParametrizedThreadStart  für Threadmethoden mit Parameter  Parameter muss vom Typ object sein
  • 17. Auszuführende Methode static void Main(string[] args) { ThreadStart TestThreadStart = new ThreadStart(ThreadMethod); Thread TestThread = new Thread(TestThreadStart); TestThread.Name = quot;Test Threadquot;; TestThread.Priority = ThreadPriority.Normal; TestThread.IsBackground = false; TestThread.Start(); Threadoptionen Console.ReadLine(); } Kein Rückgabewert static void ThreadMethod() { Console.WriteLine(quot;Thread Runquot;); }
  • 18. Auszuführende Methode static void Main(string[] args) { ParameterizedThreadStart TestThreadStart = new ParameterizedThreadStart(ThreadMethod); Thread TestThread = new Thread(TestThreadStart); TestThread.Name = quot;Test Threadquot;; TestThread.Priority = ThreadPriority.Normal; Threadoptionen TestThread.IsBackground = false; TestThread.Start(quot;Testquot;); Start mit Parameter Console.ReadLine(); } Kein Rückgabewert object Parameter static void ThreadMethod(object Parameter) { Console.WriteLine(quot;Thread Run with Parameter: quot; + Parameter.ToString()); }
  • 19. Unterscheidung zwischen  Foreground Threads  Background Threads  Thread.Join()
  • 20. Thread ForegroundThread = new Thread(new ThreadStart(ThreadMethod)); ForegroundThread.Start(); Foreground Thread Verhindert Beenden der Applikation Thread BackgroundThread = new Thread(new ThreadStart(ThreadMethod)); BackgroundThread.IsBackground = true; BackgroundThread.Start(); Background Thread kann nach Beendigung aller Foreground Threads terminiert werden
  • 21. ThreadStart operation = new ThreadStart(ThreadMethod); Thread[] theThreads = new Thread[5]; for (int x = 0; x <= 4; ++x) { theThreads[x] = new Thread(operation); theThreads[x].Start(); } Thread starten foreach (Thread oneThread in theThreads) { Console.WriteLine(quot;Waiting for Thread to terminatequot;); oneThread.Join(); Console.WriteLine(quot;Thread terminatedquot;); } Auf Threadende warten
  • 22. Bestimmt die Vorrangregelung bei der Ausführung eines Threads  Thread.Priority Eigenschaft  ThreadPriority Enum  Lowest  BelowNormal  Normal  AboveNormal  Highest
  • 23. Standardpriorität ist ThreadPriority.Normal Thread NormalPriorityThread = new Thread(new ThreadStart(ThreadMethod)); Thread HighPriorityThread = new Thread(new ThreadStart(ThreadMethod)); HighPriorityThread.Priority = ThreadPriority.Highest; NormalPriorityThread.Start(); HighPriorityThread.Start(); Setzen der Threadpriorität auf ThreadPriority.Highest
  • 24. Thread.Abort()  Löst ThreadAbortException aus  Beendet Thread nach Auslösen der Exception  Sicheres Beenden von Threads  ThreadAbortException behandeln  Alternative: Abortvariable
  • 25. static void Main(string[] args) { Thread newThread = new Thread(new ThreadStart(ThreadMethod)); newThread.Start(); Thread.Sleep(1000); newThread.Abort(); Console.ReadLine(); } Thread beenden
  • 26. static void ThreadMethod() { try { for (int i = 0; i < 100; i++) { Console.WriteLine(quot;Thread - working.quot;); Thread.Sleep(100); } } ThreadAbortException catch (ThreadAbortException e) behandeln { Console.WriteLine(quot;Thread - caught ThreadAbortException - resetting.quot;); Console.WriteLine(quot;Exception message: {0}quot;, e.Message); } finally { Console.WriteLine(quot;Just one more message before I dropquot;); } }
  • 27. Einige Programmieren raten von Thread.Abort ab  Gründe  Thread.Abort kann Thread an jeder Stelle abbrechen  Finally Statements können übergangen werden  Ressourcen können ungeschlossen bleiben  Ansatz: Abortvariable einführen und im Thread pollen
  • 28. static void TestManualAbort() { Thread newThread = new Thread(new ThreadStart(ManualAbortThreadMethod)); newThread.Start(); Thread.Sleep(1000); Abort = true; } static volatile bool Abort = false; static void ManualAbortThreadMethod() { while (true) { if (Abort == false) { Console.WriteLine(System.DateTime.Now.ToString()); } else { break; } } }
  • 29. Probleme mit Thread.Abort() lassen sich auch ohne Abortvariable umgehen  Alternative Lösungen  Code auf ThreadAbortException anpassen  Constrained Execution Regions einsetzen (Fortgeschritten)
  • 31. Vor Multithreading: Nur ein gleichzeitiger Zugriff auf Daten  Mit Multithreading: Möglichkeit des gleichzeitigen Zugriffs auf Daten von mehreren Threads  Was passiert wenn mehrere Threads gleichzeitig einen Datenbestand manipulieren?
  • 32. Mehrere Threads können eine gemeinsame Variable manipulieren  Probleme beim Rückschreiben von Werten  Fehlerhafte Werte als Ergebnis
  • 33. Thread 1 Thread 2 X = X + 30 X = X + 15 Variable einlesen Variable einlesen X=0
  • 34. Thread 1 Thread 2 X=0 X=0 X=0
  • 35. Thread 1 Thread 2 X=30 X=0 X=0
  • 36. Thread 1 Thread 2 X=30 X=15 Variable schreiben X=0
  • 37. Thread 1 Thread 2 Beenden… X=15 Variable schreiben X = 30
  • 38. Thread 2 Beenden… X = 15
  • 40. Interlocked Klasse  Synchronisierungssperren
  • 41. Bietet atomare Operationen für Variablen  Nur für triviale Operationen an einer Variable (Addieren, Dekrementieren, Vertauschen, Inkrementieren)  Effektiv, aber beschränktes Einsatzgebiet
  • 42. Monitor.Enter() + Monitor.Exit()  Lock Schlüsselwort  ReaderWriterLock  Mutex / Semaphore / AutoResetEvent / ManualResetEvent
  • 43. Setzt in Codeabschnitt eine Synchronisierungssperre  Synchronisieren auf ein Objekt  Besitzer des Monitor des Objekts erhält exklusiven Zugriff auf Codeabschnitt  Andere blockieren bis Freigabe des Monitors
  • 44. Synchronisierungsobjekt als Parameter  Umschließt Codebereich implizit mit Monitor.Enter() und Monitor.Exit()
  • 45. Sperrvariable public static object Lockvar = new object(); public static void LockMethod(object Parameter) { Monitor.Enter(Lockvar); try { Anfang count++; Synchronisierungssperre Console.WriteLine(quot;Thread quot; + count + quot; Writingquot;); finally { Monitor.Exit(Lockvar); } } Ende Synchronisierungssperre
  • 46. Sperrvariable public static object Lockvar = new object(); public static void LockMethod(object Parameter) { lock (Lockvar) Sperrvariable { count++; Console.WriteLine(quot;Thread quot; + count + quot; Writingquot;); } }
  • 47. Zwei Threads schließen sich gegenseitig durch Synchronisationssperren aus  Thread A wartet auf Thread B, Thread B wartet auf Thread A  Endloses Warten
  • 48. public static object Lockvar1 = new object(); public static object Lockvar2 = new object(); public static void DeadLockMethodOne() { lock (Lockvar1) { Sperrvariable lock (Lockvar2) Sperrt Lockvar1 { Console.WriteLine(quot;Firstquot;); } } } public static void DeadLockMethodTwo() { lock (Lockvar2) { lock (Lockvar1) Sperrt Lockvar2 { Console.WriteLine(quot;Secondquot;); } } }
  • 49. Sorgfältig Programmieren!  Monitor.TryEnter() mit Zeitlimit  Kurze Codeabschnitte sperren
  • 50. ReaderWriteLock Klasse ermöglicht  Ausschließliche Lesesperre  Schreibsperre  Wechsel von Lese zu Schreibsperre und vice versa
  • 51. Oder noch eine Pause?
  • 52. Erstellung eigener Threads oft unnötig  ThreadPool verwaltet Threads die auf Abruf bereit stehen, Standardanzahl 25  Overhead bei Threaderstellung und Threadvernichtung eliminiert  ThreadPool Threads sind Hintergrundthreads  ThreadPool Arbeitsaufgaben können nicht durch Fremdeinwirkung abgebrochen werden
  • 53. ThreadPool.QueueUserWorkItem  Übergabe von Verweis auf Funktion  Optional: Übergabe von Parameter  ThreadPool.GetMaxThreads  Anzahl der maximal verfügbaren Threads abrufen  ThreadPool.SetMaxThreads  Anzahl der maximal verfügbaren Threads festlegen
  • 54. WaitCallback Delegate Thread mit Parameter starten WaitCallback workItem = new WaitCallback(ThreadMethod); if (!ThreadPool.QueueUserWorkItem(workItem, quot;ThreadPooledquot;)) { Console.WriteLine(quot;Element konnte nicht in Warteschlange gestellt werdenquot;); }
  • 55. Idee: Asynchrones Starten & Beenden eines Ablaufs  Vorteile  Keine manuelle Verwaltung des Threads notwendig  Automatische Threadskalierung  Performancegewinn durch automatische Nutzung von ThreadPool  3 Verwendungsmodelle  Warten-bis-fertig Modell  Pollingmodell  Rückrufmodell
  • 56. Asynchrone Operation starten  Andere Arbeiten erledigen  Mit EndXXX auf Ende der Operation warten
  • 57. Andere Arbeiten ausführen Console.WriteLine(quot;Start Async Fetchin..quot;); GenericMethodDelegate<int> method = IntFetcher.Fetch; IAsyncResult ar = method.BeginInvoke(null, method); Methode asynchron Thread.Sleep(1000); ausführen Console.WriteLine(quot;Got quot; + method.EndInvoke(ar)); Console.WriteLine(quot;End Async Fetchin..quot;); Auf Ende der Methode warten
  • 58. Starten der asnychronen Operation  Regelmäßig überprüfen ob die Operation abgeschlossen ist  Nach Abgeschlossener Operation EndXXX aufrufen
  • 59. Andere Arbeiten ausführen Console.WriteLine(quot;Start Async Fetchin..quot;); IAsyncResult ar2 = method.BeginInvoke(null, method); Methode asynchron while (!ar2.IsCompleted) ausführen { Thread.Sleep(1000); } Regelmäßig pollen Console.WriteLine(quot;Got quot; + method.EndInvoke(ar2)); Console.WriteLine(quot;End Async Fetchin..quot;); Ergebnis abrufen (keine Wartezeit)
  • 60. Starten der asynchronen Operation mit Übergabe einer Rückruffunktion
  • 61. Andere Arbeiten ausführen Callback Funktion angeben Console.WriteLine(quot;Start Async Fetchin..quot;); IAsyncResult ar3 = method.BeginInvoke(new AsyncCallback(CompleteFetch), method); Thread.Sleep(1000); static void CompleteFetch(IAsyncResult result) { GenericMethodDelegate<int> method = (GenericMethodDelegate<int>)result.AsyncState; int i = method.EndInvoke(result); Console.WriteLine(quot;Got quot; + i); Console.WriteLine(quot;End Async Fetchin...quot;); } Ergebnis abrufen (keine Wartezeit)
  • 62. Try Catch bei Aufruf der EndXXX Methode anwenden try { Console.WriteLine(quot;Got quot; + method.EndInvoke(ar2)); } catch { Console.WriteLine(quot;Error occuredquot;); } finally { Console.WriteLine(quot;End Async Fetchin..quot;); }
  • 63. Delegaten erstellen  BeginInvoke des Delegaten aufrufen  EndInvoke des Delegaten aufrufen
  • 64. Delegat auf auszuführende Methode public delegate TOutput GenericMethodDelegate<TOutput>(); Methode dem Delegat static void TestAsync() zuweisen { Console.WriteLine(quot;Start Async Fetchin..quot;); GenericMethodDelegate<int> method = IntFetcher.Fetch; IAsyncResult ar = method.BeginInvoke(null, method); Thread.Sleep(1000); Console.WriteLine(quot;Got quot; + method.EndInvoke(ar)); Console.WriteLine(quot;End Async Fetchin..quot;); } Blockieren bis asynchrone Methode asynchron starten Methode beendet
  • 65. Ruft eine Methode asynchron nach Zeitspanne auf  Wiederholt Aufruf der Methode nach Zeitspanne  Timer.Change
  • 66. Tick Intervall TimerCallbackDelegate Startverzögerung static void TestTimer() { Timer tm = new Timer(new TimerCallback(ThreadMethod), quot;Timerquot;, 0, 1000); Thread.Sleep(1000); tm.Change(0, 100); } Parameter Intervall / Verzögerung ändern
  • 67. Häufigster Anwendungsfall für Threading: Rechenlast aus GUIs auslagern  Dem Hauptthread möglichst wenig Rechenlast zuordnen  Rechenlast in Hauptthread verursacht hängende GUIs  Problematik: Zugriff auf Steuerelemente von Threads aus
  • 68. private void cmdThreaded_Click(object sender, EventArgs e) { Thread FormsThread = new Thread(new ThreadStart(DoWork)); FormsThread.Start(); } private void cmdUnthreaded_Click(object sender, EventArgs e) { DoWork(); }
  • 69.
  • 70. private void button1_Click(object sender, EventArgs e) { Thread FormsThread = new Thread(new ThreadStart(ManipulateList)); FormsThread.Start(); } private void ManipulateList() { listBox1.Items.Add(quot;testquot;); }
  • 71.
  • 72. Direktes Manipulieren von Windows Forms Steuerelementen löst Exception aus  Mit Invoke den UI Thread auffordern Manipulationen vorzunehmen  Delegaten übergeben  Asynchroner Aufruf ebenfalls möglich  Optional: Eine Methode für Invoke und Direkt mit InvokeRequired Eigenschaft
  • 73. Delegat nach Funktion erstellen private delegate void ManipulateListDelegate(); private void ManipulateList() Invoke benötigt? { if (listBox1.InvokeRequired == true) { listBox1.Invoke(new ManipulateListDelegate(ManipulateList)); } Invoke aufrufen mit Verweis else auf Methode { listBox1.Items.Add(quot;testquot;); } } Manipulationen vornehmen