🏗️ Einführung in Concurrency¶
🚀 1. Einführung in Concurrency¶
Concurrency (Nebenläufigkeit) bezeichnet die Fähigkeit eines Systems, mehrere Aufgaben gleichzeitig auszuführen. Moderne Betriebssysteme und Multi-Core-Prozessoren machen Concurrency zu einem wesentlichen Konzept.
Warum Concurrency?¶
- Effizienz: Optimale Nutzung von CPU-Kernen.
- Reaktionsfähigkeit: Erhöht die Interaktivität von Anwendungen.
- Skalierbarkeit: Bessere Performance auf Multi-Core-Systemen.
🧵 2. Threads: Grundlagen & API¶
Was sind Threads?¶
Ein Thread ist eine leichtgewichtige Untereinheit eines Prozesses. Mehrere Threads eines Prozesses teilen sich denselben Speicherraum.
Threads in verschiedenen Sprachen¶
⚠️ 3. Race Conditions & Synchronisation¶
Race Condition¶
Ein Race Condition tritt auf, wenn mehrere Threads gleichzeitig auf eine geteilte Ressource zugreifen und das Ergebnis von der Reihenfolge der Zugriffe abhängt.
Beispiel einer Race Condition in C¶
```c
#include <pthread.h>
#include <stdio.h>
int counter = 0;
void* increment(void* arg) {
for (int i = 0; i < 100000; i++) {
counter++; // 🔴 Race Condition! !!FIX MIT LOCKS!!
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Counter: %d\\n", counter); // ❌ Inkonsistentes Ergebnis!
return 0;
```
Lösung: Synchronisation mit Locks¶
🔐 4. Locks, Semaphoren & Deadlocks¶
🔒 Mutex (Mutual Exclusion)¶
Ein Mutex erlaubt nur einem Thread den Zugriff auf eine kritische Sektion.
🚦 Semaphore¶
Ein Semaphore begrenzt die Anzahl der Threads, die gleichzeitig auf eine Ressource zugreifen können.
Beispiel eines Semaphores in C¶
🐞 Deadlocks & Avoidance¶
Ein Deadlock tritt auf, wenn zwei Threads auf Ressourcen warten, die der jeweils andere blockiert.
Deadlock-Szenario¶
- Thread A hält Lock 1, wartet auf Lock 2.
- Thread B hält Lock 2, wartet auf Lock 1.
Lösung:
- Locking-Order: Immer in der gleichen Reihenfolge sperren.
- Deadlock-Erkennung: OS kann zirkuläre Wartezustände auflösen.
⚡ 5. Thread-Kommunikation & Scheduling¶
Thread-Scheduling¶
- Preemptive Scheduling: OS kann Threads unterbrechen.
- Cooperative Scheduling: Threads geben die Kontrolle explizit zurück.
Bedingungsvariablen (Condition Variables)¶
Erlauben es Threads, zu warten, bis eine Bedingung erfüllt ist.
Beispiel in C mit pthread_cond_t
¶
pthread_cond_t cond;
pthread_mutex_t lock;
void* producer(void* arg) {
pthread_mutex_lock(&lock);
pthread_cond_signal(&cond); // Weckt einen wartenden Thread auf
pthread_mutex_unlock(&lock);
}
🛠️ 6. Debugging von Concurrency-Fehlern¶
Häufige Concurrency-Fehler¶
- Race Conditions → Verwenden von Locks/Semaphoren.
- Deadlocks → Lock-Order festlegen.
- Starvation → Fairness durch Prioritätsregeln sicherstellen.
Tools für Debugging¶
- Valgrind (Helgrind) für C: Erkennung von Race Conditions.
- ThreadSanitizer für C++ & Rust: Detektiert Data Races.
- GDB für Threads: Debugging auf niedriger Ebene.
✅ 7. Best Practices für Multi-Threaded-Programmierung¶
🔹 Best Practices¶
✅ Verwende Mutexe oder Semaphoren, um kritische Abschnitte zu schützen.
✅ Nutze Thread-Pools, um Performance zu optimieren.
✅ Setze Atomic Operations ein, wenn nur einfache Werte modifiziert werden müssen.
✅ Vermeide zu viele Locks, um Deadlocks zu verhindern.
✅ Nutze Parallelisierungs-Patterns wie Map-Reduce oder Worker-Threads.
📌 Fazit¶
- Concurrency ist essenziell für moderne Software.
- Threads verbessern Performance, erfordern aber Synchronisation.
- Race Conditions und Deadlocks sind typische Probleme.
- Debugging-Tools helfen, Fehler frühzeitig zu erkennen.
- Gute Planung und Best Practices sind entscheidend für stabile Programme.