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
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
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
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
41. Bietet atomare Operationen für Variablen
Nur für triviale Operationen an einer Variable
(Addieren, Dekrementieren, Vertauschen,
Inkrementieren)
Effektiv, aber beschränktes Einsatzgebiet
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;);
}
}
}
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
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
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