Informatik

Synchronisation: Nebenläufige Prozesse sicher steuern

Synchronisation: Nebenläufige Prozesse sicher steuern
Synchronisation: Nebenläufige Prozesse sicher steuern
Für Quiz, Lückentext, Lernkarten und Fortschritt ist JavaScript nötig. Alle Inhalte und Lösungen bleiben direkt lesbar.

Synchronisation stimmt nebenläufige Prozesse oder Threads so aufeinander ab, dass sie gemeinsame Daten und begrenzte Ressourcen kontrolliert nutzen. Sie verhindert unter anderem, dass eine ungünstige Reihenfolge von Zugriffen Daten verfälscht.

Auf dieser Seite untersuchst du einen solchen Fehler, erkennst kritische Abschnitte und entscheidest, welcher Synchronisationsmechanismus zu einer Situation passt.

Deine Lernziele

Hake ab, was du schon kannst — und komm am Ende hierher zurück!

Was Synchronisation koordiniert

Stell dir zwei Threads vor, die dasselbe Bankguthaben verändern. Beide können grundsätzlich korrekt programmiert sein. Trotzdem kann ein falscher Endwert entstehen, wenn ihre einzelnen Schritte ungünstig ineinandergreifen.

Definition

Prozesssynchronisation

Prozesssynchronisation koordiniert den zeitlichen Ablauf nebenläufiger Prozesse oder Threads. Sie legt fest, wann ein Prozess fortfahren darf, auf ein Ereignis warten muss oder eine gemeinsam genutzte Ressource verwenden darf.

Nebenläufig bedeutet: Die Arbeitsschritte mehrerer Prozesse können sich zeitlich überlappen oder abwechseln. Entscheidend ist nicht, ob tatsächlich mehrere Prozessorkerne gleichzeitig rechnen. Schon eine verschachtelte Ausführung auf einem Kern kann Synchronisationsfehler auslösen.

Synchronisation erfüllt verschiedene Aufgaben:

  • Sie schützt gemeinsame Daten vor widersprüchlichen Änderungen.
  • Sie teilt begrenzte Ressourcen wie Geräte zu.
  • Sie ordnet Ereignisse, wenn ein Prozess auf einen anderen warten muss.
  • Sie unterstützt die Übergabe von Informationen zwischen Prozessen.

Dateisynchronisation verfolgt ein anderes Ziel: Sie bringt Datenbestände mehrerer Speicherorte auf einen gemeinsamen Stand. Auf dieser Seite geht es dagegen um die Koordination nebenläufiger Prozesse.

Teste dich
Frage 1 von 1LeichtWelche Situation benötigt Prozesssynchronisation?
Lösung: Zwei Threads verändern dasselbe Guthaben. — Synchronisation wird nötig, wenn nebenläufige Abläufe voneinander abhängen oder gemeinsame Daten beziehungsweise Ressourcen verwenden.
Wie eine Race Condition entsteht

Ausgangswert eines Kontos: 3000 Euro. Zwei Prozesse führen fast gleichzeitig eine Abhebung aus:

  • Prozess A möchte 500 Euro abheben.
  • Prozess B möchte 2300 Euro abheben.

Jede Abhebung besteht aus mehreren Schritten: Guthaben lesen, Rest berechnen, Rest prüfen und neuen Wert schreiben.

Beispiel

Eine fehlerhafte Verschachtelung kann so ablaufen:

  1. A liest 3000 und berechnet 2500.
  2. A wird vor dem Schreiben unterbrochen.
  3. B liest noch 3000, berechnet 700 und schreibt 700.
  4. B zahlt 2300 Euro aus.
  5. A setzt seine Arbeit mit dem alten Zwischenwert fort und schreibt 2500.
  6. A zahlt 500 Euro aus.

Insgesamt wurden 2800 Euro ausgezahlt. Das Konto müsste deshalb 200 Euro enthalten. Angezeigt werden aber 2500 Euro, weil A die Änderung von B überschrieben hat.

Definition

Race Condition

Eine Race Condition liegt vor, wenn das Ergebnis davon abhängt, in welcher zeitlichen Reihenfolge sich nebenläufige Zugriffe verschachteln.

Das Überschreiben einer zwischenzeitlichen Änderung heißt Lost Update, also verlorene Aktualisierung. Der Fehler ist schwer zu finden, weil andere Ausführungsreihenfolgen ein korrektes Ergebnis liefern können.

Bei einer vollständigen seriellen Ausführung A vor B oder B vor A bleibt jeweils das korrekte Guthaben von 200 Euro übrig. Die einzelnen Abhebungen sind also nicht grundsätzlich falsch. Problematisch ist ihre ungeschützte Verschachtelung.

Merke

Teste nebenläufigen Code nicht nur mit einer einzigen Reihenfolge. Ein korrektes Ergebnis in einem Test beweist nicht, dass andere Verschachtelungen ebenfalls korrekt sind.

Teste dich
Frage 1 von 1MittelB liest 3000 und berechnet 700, wird aber vor dem Schreiben unterbrochen. Danach führt A seine Abhebung vollständig aus und schreibt 2500. Zum Schluss schreibt B seinen alten Zwischenwert. Welcher Endwert bleibt?
Lösung: 700 Euro — B setzt nach der Unterbrechung mit seinem bereits berechneten Wert 700 fort. Dieser Wert überschreibt die 2500 von A. Auch 700 ist falsch, denn insgesamt wurden 2800 Euro ausgezahlt.
Wie ein kritischer Abschnitt geschützt wird

Die Folge „lesen, berechnen, prüfen, schreiben“ greift auf den gemeinsamen Zustand guthaben zu. Sie darf nicht von einer zweiten Abhebung überlappt werden.

Definition

Kritischer Abschnitt

Ein kritischer Abschnitt ist ein Teil eines Programms, der auf gemeinsam genutzte veränderliche Daten oder Ressourcen zugreift und deshalb vor konkurrierenden Zugriffen geschützt werden muss.

Der gesamte zusammengehörige Vorgang muss atomar erscheinen: Für andere Prozesse wirkt er wie ein einziger unteilbarer Schritt. Nur den Schreibbefehl zu schützen reicht beim Bankbeispiel nicht. Beide Prozesse könnten den gleichen alten Wert schon vorher gelesen haben.

Eine typische Struktur sieht so aus:

text enter_cs(Ressource) gemeinsamen Wert lesen neuen Wert berechnen und prüfen gemeinsamen Wert schreiben leave_cs(Ressource)

enter_cs wartet, bis der geschützte Bereich frei ist. leave_cs gibt ihn anschließend wieder frei.

Eine gute Steuerung kritischer Abschnitte muss mehrere Anforderungen erfüllen:

  1. Gegenseitiger Ausschluss (Mutual Exclusion): Höchstens ein Prozess befindet sich im geschützten Abschnitt.
  2. Fortschritt: Ein Eintrittswunsch wird schließlich erfüllt. Es entsteht weder Deadlock noch dauerhaftes Verhungern.
  3. Unabhängigkeit: Prozesse außerhalb des kritischen Abschnitts behindern den darin arbeitenden Prozess nicht unnötig.
  4. Keine Geschwindigkeitsannahme: Die Lösung darf nicht davon abhängen, welcher Prozess normalerweise schneller ist.
Teste dich
Frage 1 von 1MittelWelcher Teil des Bankbeispiels muss als Einheit geschützt werden?
Lösung: Das Lesen, Berechnen, Prüfen und anschließende Schreiben des Guthabens — Alle Schritte, die aus dem gemeinsamen Ausgangswert einen neuen gültigen Zustand ableiten, gehören zum kritischen Abschnitt.
Welcher Mechanismus passt

Nicht jeder Synchronisationsmechanismus wartet auf dieselbe Weise. Die erwartete Wartezeit und die Anzahl verfügbarer Ressourcen helfen bei der Auswahl.

Mutex: genau ein Prozess im Abschnitt

Ein Mutex schützt einen kritischen Abschnitt durch gegenseitigen Ausschluss. Ein Prozess sperrt ihn vor dem Zugriff und gibt ihn danach wieder frei. Andere Prozesse müssen warten, solange die Sperre belegt ist.

Für die Abhebung genügt ein gemeinsamer Mutex um die vollständige Lese-Änderungs-Schreib-Folge. Dadurch sieht die zweite Abhebung erst den bereits aktualisierten Kontostand.

Semaphor: blockieren und Ressourcen zählen

Definition

Semaphor

Ein Semaphor ist ein abstrakter Datentyp mit einem Zähler und einer Warteschlange. Seine Operationen prüfen und verändern den Zustand atomar.

Ein binärer Semaphor kann einen einzelnen kritischen Abschnitt schützen. Ein zählender Semaphor erlaubt dagegen bis zu einer festgelegten Anzahl gleichzeitiger Nutzungen. Bei einem Anfangswert von 3 könnten beispielsweise höchstens drei Prozesse gleichzeitig drei gleichartige verfügbare Ressourcen belegen.

Die Warteoperation wird oft P(), wait() oder down() genannt. Die Freigabe heißt unter anderem V(), signal() oder up(). Ist kein Eintritt möglich, kann der wartende Prozess blockiert werden, sodass ein anderer Prozess Rechenzeit erhält.

Spinlock: aktiv auf eine kurze Freigabe warten

Ein Spinlock prüft die Sperre fortlaufend. Dieses aktive Warten verbraucht Rechenzeit, während der Prozess keinen fachlichen Fortschritt macht. Das atomare Setzen der Sperre benötigt Hardwareunterstützung; getrenntes Prüfen und anschließendes Setzen wäre erneut durch eine Race Condition gefährdet.

In der zugrunde liegenden Betriebssystemdarstellung sind Spinlocks für sehr kurze Abschnitte im Kernel vorgesehen. Für längere oder unbekannt lange Wartezeiten sind blockierende Mechanismen geeigneter.

Merke

Kurze erwartete Wartezeit im Kernel kann für einen Spinlock sprechen. Bei längerer oder unklarer Wartezeit soll ein Prozess blockieren, statt ständig zu prüfen.

Teste dich
Frage 1 von 2MittelDrei identische Geräte dürfen gleichzeitig von höchstens drei Prozessen genutzt werden. Welcher Mechanismus bildet diese Grenze direkt ab?
Lösung: Ein zählender Semaphor mit Anfangswert 3 — Ein zählender Semaphor verwaltet mehrere gleichartige Nutzungserlaubnisse. Jede Belegung verringert und jede Freigabe erhöht den Zähler atomar.
Frage 2 von 2SchwerEin kritischer Kernelabschnitt dauert nur sehr kurz. Blockieren und späteres Aufwecken wären aufwendig. Welche Wahl ist begründbar?
Lösung: Ein Spinlock, sofern das Setzen der Sperre atomar erfolgt — Die Kürze beseitigt die Race Condition nicht. Sie kann aber aktives Warten vertretbar machen, wenn der Spinlock korrekt atomar implementiert ist.
Welche Fortschrittsprobleme drohen

Gegenseitiger Ausschluss allein genügt nicht. Prozesse müssen auch weiterkommen können.

Definition

Deadlock

Bei einem Deadlock warten Prozesse dauerhaft auf Ereignisse oder Ressourcen, die nur voneinander ausgelöst beziehungsweise freigegeben werden könnten.

Ein typisches Muster ist eine zyklische Wartebeziehung: Prozess A hält Ressource 1 und wartet auf Ressource 2. Prozess B hält Ressource 2 und wartet auf Ressource 1. Keiner kann fortfahren.

Definition

Livelock

Bei einem Livelock bleiben Prozesse aktiv und reagieren aufeinander, erzielen aber keinen Fortschritt.

Das kann passieren, wenn zwei Prozesse bei jedem Konflikt gleichzeitig zurückweichen und es anschließend wieder gleichzeitig versuchen. Im Unterschied zum Deadlock wird weiter gerechnet, aber die eigentliche Aufgabe bleibt unerledigt.

Verhungern bedeutet: Ein bestimmter wartender Prozess kommt dauerhaft nicht zum Zug, obwohl andere Prozesse weiterhin Fortschritt machen. Eine Leserbevorzugung kann beispielsweise einen Schreiber immer wieder zurückstellen, wenn fortlaufend neue Leser eintreffen.

ProblemAktivitätFortschritt
DeadlockProzesse warten dauerhaftNiemand im Zyklus kommt weiter
LivelockProzesse bleiben aktivNiemand löst die Aufgabe
VerhungernAndere Prozesse arbeiten weiterEin bestimmter Prozess wartet unbegrenzt
Teste dich
Frage 1 von 3LeichtZwei Prozesse halten je eine Ressource und warten dauerhaft auf die Ressource des anderen. Was liegt vor?
Lösung: Deadlock — Die zyklische Wartebeziehung verhindert jede Freigabe und damit jeden weiteren Eintritt.
Frage 2 von 3MittelZwei Prozesse ziehen bei jedem Konflikt ihre Wünsche zurück und starten sofort erneut. Beide bleiben aktiv, gelangen aber nie in den kritischen Abschnitt. Was liegt vor?
Lösung: Livelock — Fortgesetzte Aktivität ohne fachlichen Fortschritt kennzeichnet einen Livelock.
Frage 3 von 3SchwerEin Leser-Schreiber-System lässt stets neu eintreffende Leser vor. Ein wartender Schreiber kommt deshalb nie zum Zug. Welches Problem zeigt sich?
Lösung: Verhungern des Schreibers — Verhungern betrifft einen dauerhaft übergangenen Prozess, während andere Prozesse weiterarbeiten.
Karteikasten
Karteikasten

Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.

Alles auf einen Blick
Mindmap
  • Prozesssynchronisation
    • Ausgangspunkt: nebenläufige Zugriffe auf gemeinsame Daten oder Ressourcen
    • Fehlerbild: Race Condition kann ein Lost Update erzeugen
    • Schutzbereich: kritischer Abschnitt muss atomar erscheinen
    • Mechanismen: Mutex, Semaphor oder Spinlock
    • Auswahl: Exklusivität, Ressourcenanzahl und Wartezeit beachten
    • Fortschritt: Deadlock, Livelock und Verhungern verhindern
Abschluss-Check
Teste dich
Frage 1 von 3LeichtWoran erkennst du eine Race Condition?
Lösung: Unterschiedliche zulässige Verschachtelungen können unterschiedliche Ergebnisse erzeugen. — Entscheidend ist die Abhängigkeit des Ergebnisses von der Ausführungsreihenfolge, nicht echte Gleichzeitigkeit auf mehreren Kernen.
Frage 2 von 3MittelZwei Threads erhöhen einen gemeinsamen Zähler jeweils durch Lesen, Addieren und Schreiben. Was muss geschützt werden?
Lösung: Die gesamte Lese-Änderungs-Schreib-Folge — Der neue Wert hängt vom gelesenen gemeinsamen Ausgangswert ab. Deshalb bilden Lesen, Ändern und Schreiben zusammen den kritischen Abschnitt.
Frage 3 von 3SchwerEin Server besitzt vier gleichartige Verbindungen. Eine Operation kann länger dauern, und höchstens vier Prozesse dürfen gleichzeitig eine Verbindung verwenden. Welche Lösung ist am passendsten begründet?
Lösung: Ein zählender Semaphor mit vier Erlaubnissen, der weitere Prozesse blockiert — Der zählende Semaphor bildet die Anzahl verfügbarer Ressourcen direkt ab. Blockieren verhindert unkontrolliertes aktives Warten, wenn alle vier Verbindungen belegt sind.

Du beherrschst das Thema, wenn du bei einem verschachtelten Ablauf zuerst den gemeinsamen Zustand und den kritischen Abschnitt markierst, danach einen passenden Schutz auswählst und schließlich prüfst, ob alle wartenden Prozesse noch Fortschritt machen können.

Passend dazu