Threading Arthur Zaczek Aug 2015 Threading 1 Threading 1.1 Motivation Threading erlaubt die gleichzeitige Ausführung von mehreren Programmteilen. • mehrere gleichzeitige Anfragen: Webserver, Datenbank • (zu) lange laufende Berechnungen: Scientific Computing, Spiele, User Interfaces • mit aktuellen Multi Core Prozessoren: eigentlich überall 1.2 • • • • 1.3 • • • • • • 2 Begriffe Prozess: Eine gestartete Anwendung im Betriebssystem Thread: Ausführungsstrang innerhalb eines Prozesses Multi-Processing: Abarbeitung mehrerer Aufgaben in verschiedenen Prozessen Multi-Threading: Abarbeitung mehrerer Aufgaben in verschiedenen Threads eines Prozesses Nachteile hohe Komplexität hohe Fehleranfälligkeit erfordert oft globales Denken Programmablauf normalerweise nicht exakt reproduzierbar subtile Fehler können bei Entwicklung nie schlagend werden, aber immer beim Kunden macht neue Algorithmen und Datenstrukturen notwendig Synchronisierung 2.1 Serialisierbarkeit Die gleichzeitige Abarbeitung aller Threads sollte das gleiche Ergebnis wie eine (beliebige) hintereinander-Ausführung liefern. 2.2 Einfacher Fall • Aufgaben mit minimalem Kommunikationsaufwand zwischen Threads • Beispiele: – Webserver für statische Seiten – Batch-Rendering von 3D-Szenen • Erfordert Synchronisation nur zum Abholen der Ergebnisse 2.3 Einfacher Fall - II void Main() { List<Thread> threads = new List<Thread>(); // Arbeit verteilen 1 Threading for (int i = 0; i < 4; i++) { threads.Add(new RenderThread(i)); threads[i].Start(); } Bild ergebnis = new Bild(2560, 2560); foreach (var thread in threads) { thread.Join(); // Teilbild schreiben thread.SchreibeErgebnis(ergebnis); } } 2.4 Einfacher Fall - III Wenn Threads nicht miteinander kommunizieren, ist das ausreichend um Serialisierbarkeit zu garantieren Figure 1: Serialisierbarkeit 3 Programmieren 3.1 Klasse “Thread” Java java.lang.Thread CS System.Threading.Thread • Klasse, um neue Threads zu verwalten • Erzeugt neuen Ausführungsfaden 2 Threading 3.2 • • • • • • 4 Opertationen start(): Startet einen neuen Thread sleep(Millisekunden): Pausiert den Thread (unschön!) join(): Warten auf das Ende eines Threads join(Millisekunden): mit Timeout interrupt(): signalisiert eine “Unterbrechung” an den Thread Abort() [C#]: bricht den Thread ab Java 4.1 Java http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html Zwei Wege um einen Thread zu starten: 1. Runnable implementieren 2. Thread ableiten 4.2 Runnable public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } } 4.3 Thread ableiten public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloThread()).start(); } } 4.4 Kurze Demo Java 3 Threading 4.5 C# - schnellste Variante class Program { static void Main(string[] args) { Thread t = new Thread(Run); t.Start(); } private static void Run() { Console.WriteLine("Hello from Thread"); } } 4.6 C# - eigene Klasse public class MyThread { private Thread thread = null; public MyThread() { this.thread = new Thread(Run); } private void Run() { Console.WriteLine("Hello from Thread"); } } 4.7 Kurze Demo C# 4.8 Threads pausieren Thread.sleep(ms); • Kostet keine CPU Zeit • ACHTUNG! Ist in vielen Situationen unelegant • Events? 4.9 Join t.join() • join() wartet so lange, bis der Thread beendet wurde • Mit einer Überladung kann man die max. Wartezeit angeben • Dient der Synchronisierung 4 Threading 5 Threadübergreifende Kommunikation 5.1 Threadübergreifende Kommunikation public void Transfer(Konto ziel, int betrag) { this.Guthaben -= betrag; ziel.Guthaben += betrag; } Was könnte passieren, wenn zwei Threads gleichzeitig Transfer() auf dem selben Konto ausführen? 5.2 Race Condition var tmp = this.Guthaben - betragA var tmp = this.Guthaben - betragB this.Guthaben = tmp this.Guthaben = tmp Hängt das Ergebnis von der Ausführungsreihenfolge der einzelnen Berechnungsschritte ab, kann das sehr unangenehme Folgen haben 5.3 Locking mit Schlüsselwort • Java: synchronized • C#: lock 5.4 Java private final static Object syncObj = new Object(); public void transfer(Konto ziel, int betrag) { synchronized(syncObj) { this.Guthaben -= betrag; ziel.Guthaben += betrag; } } 5.5 Java 2 public synchronized void transfer(Konto ziel, int betrag) { this.Guthaben -= betrag; ziel.Guthaben += betrag; } 5 Threading In diesem Fall ungeeignet, da synchronized nur die eigene Instanz schützt, nicht aber das Konto ziel! 5.6 CS private readonly static object syncObj = new object(); public void Transfer(Konto ziel, int betrag) { lock(syncObj) { this.Guthaben -= betrag; ziel.Guthaben += betrag; } } 5.7 Kurze Demo 1. Java, C# 2. OSPC Parallel.ForEach Auswirkung 6