Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Kapitel 10 Nebenläufigkeit und wechselseitiger Ausschluss

Ähnliche Präsentationen


Präsentation zum Thema: "Kapitel 10 Nebenläufigkeit und wechselseitiger Ausschluss"—  Präsentation transkript:

1 Kapitel 10 Nebenläufigkeit und wechselseitiger Ausschluss
RW-Systemarchitektur Kap. 10

2 Überblick Betriebssysteme
6 Einführung 7 Prozesse, Fäden (threads), Scheduling 8. Speicherverwaltung 9 Dateisysteme 10 Nebenläufigkeit und wechselseitiger Ausschluss 10.1 Softwarelösungen für wechselseitigen Ausschluss 10.2 Wechselseitiger Ausschluss in Hardware 10.3 Wechselseitiger Ausschluss ins Betriebssystem integriert 11 Deadlocks 12 historisches 13 aktuelle Forschung RW-Systemarchitektur Kap. 10

3 Nebenläufigkeit Hier:
Größere Softwaresysteme sind häufig realisiert als eine Menge von nebenläufigen Prozessen. Nebenläufigkeit = „potentieller Parallelismus“ Nebenläufige Prozesses können parallel auf mehreren Prozessoren ausgeführt werden. Sie können aber auch „pseudo-parallel“ auf einem Prozessor ausgeführt werden. Grundlegende Fragestellungen: Zugriff auf gemeinsame Ressourcen? Koordination, Kommunikation Bei Zugriff auf gemeinsame Ressourcen muss häufig exklusiver Zugriff durch wechselseitiger Ausschluss garantiert werden! Hier: Softwarelösungen Hardware-Lösungen Integration ins Betriebssystem RW-Systemarchitektur Kap. 10

4 Ein einfaches Beispiel
void echo() { chin = getchar(); /* Zeichen einlesen, speichern in Variable chin */ putchar (chin); /* Zeichen ausgeben */ } Annahme: 2 Threads führen (u.a.) diesen Code aus. Threads haben einen gemeinsamen Adressraum. ) Variable chin ist eine gemeinsame Ressource! Mögliche Ausführungsreihenfolge: Thread 1 liest Zeichen, wird unterbrochen ) Thread 2 Thread 2 führt Prozedur komplett aus. Thread 1 führt Rest der Prozedur aus. Problem: Semantik verändert sich mit dem Thread-Schedule! Unterbrechung hat Effekt auf gemeinsame Variable. RW-Systemarchitektur Kap. 10

5 Produzenten-Konsumenten-Problem
Paradigma für kooperierende Prozesse: Prozess producer produziert Information, welche von einem Prozess consumer konsumiert wird. Zwischen producer und consumer gibt es einen zyklischen Puffer buffer fester Größe. Gemeinsamer Puffer #define BUFFER_SIZE 10 typedef struct { . . . } item; item buffer[BUFFER_SIZE]; int in = 0; int out = 0; RW-Systemarchitektur Kap. 10

6 Beschränkter Puffer – Insert() und Remove()
out buffer producer consumer while (true) { /* Produziere ein Element */ while (((in = (in + 1) % BUFFER_SIZE) == out) ; /* do nothing -- no free buffers */ buffer[in] = item; in = (in + 1) % BUFFER SIZE; } while (true) { while (in == out) ; /* tue nichts – nichts im Puffer */ /* entferne ein Element aus Puffer */ item = buffer[out]; out = (out + 1) % BUFFER SIZE; return item; } RW-Systemarchitektur Kap. 10

7 Produzent-Konsument mit beschränktem Puffer – Was geht schief?
Geschwindigkeit Produzent > Geschwindigkeit Konsument  Pufferinhalte werden überschrieben. Geschwindigkeit Produzent < Geschwindigkeit Konsument  Konsument liest leere Pufferfelder Korrektheit hängt von der relativen Geschwindigkeit der beiden Threads zueinander ab – nur korrekt bei gleicher Geschwindigkeit und „günstiger Initialisierung“. RW-Systemarchitektur Kap. 10

8 Beschränkter Puffer – Insert() und Remove()
out buffer while (true) { /* Produziere ein Element */ while (((in = (in + 1) % BUFFER_SIZE) == out) ; /* do nothing -- no free buffers */ buffer[in] = item; in = (in + 1) % BUFFER SIZE; } while (true) { while (in == out) ; // do nothing -- nothing to consume // remove an item from the buffer item = buffer[out]; out = (out + 1) % BUFFER SIZE; return item; } RW-Systemarchitektur Kap. 10

9 Nebenläufigkeit Grundlegende Fragen bei Nebenläufigkeit:
Betriebssystem muss Ressourcen der aktiven Prozesse verwalten. Es muss wechselseitigen Ausschluss bei gemeinsamen Ressourcen garantieren können. Die Korrektheit des Ergebnisses muss unabhängig von der relativen Ausführungsgeschwindigkeit der einzelnen Prozesse sein. Kontrollprobleme: Wechselseitiger Ausschluss, d.h. jeweils nur ein Prozess im „kritischen Abschnitt“ (= der Teil des Programms, der auf gemeinsame, exklusive Ressourcen zugreift) Verhindere Deadlocks (Blockierung aller Prozesse) Verhindere Livelocks (Prozess nicht blockiert, macht aber keinen Fortschritt). RW-Systemarchitektur Kap. 10

10 Anforderungen an wechselseitigen Ausschluss
Höchstens ein Prozess im kritischen Abschnitt. Jeder Prozess hält sich nur endliche Zeit im kritischen Abschnitt auf. Wenn ein Prozess in den kritischen Abschnitt will, so muss er nur endliche Zeit darauf warten. Wenn kein Prozess im kritischen Abschnitt ist, so wird ein interessierter Prozess ohne Verzögerung akzeptiert. Alles funktioniert unabhängig von der relativen Ausführungsgeschwindigkeit der Prozesse. RW-Systemarchitektur Kap. 10

11 10.1 Softwarelösungen für wechselseitigen Ausschluss
Hier: 5 verschiedene Lösungsversuche für wechselseitigen Ausschluss Analyse der einzelnen Lösungen Letzter Versuch entspricht der Lösung von Peterson (1981) Lösung von Peterson ist eine Vereinfachung des Algorithmus von Dekker (Anfang der 60er Jahre). RW-Systemarchitektur Kap. 10

12 Versuch 1 Voraussetzung: 2 Prozesse konkurrieren um eine Ressource
Gemeinsame Variable turn besagt, wer dran ist. turn ist mit beliebigem Wert initialisiert. /* Prozess 0 */ repeat { while (turn  0) tue nichts; /* kritischer Abschnitt */ turn := 1; /* nichtkrit. Abschnitt */ } /* Prozess 1 */ repeat { while (turn  1) tue nichts; /* kritischer Abschnitt */ turn := 0; /* nichtkrit. Abschnitt */ } RW-Systemarchitektur Kap. 10

13 Versuch 1: Analyse Vorteil: Nachteil:
Wechselseitiger Ausschluss ist garantiert. Nachteil: „Busy waiting“ = aktives Warten („while (turn  0) tue nichts;”) ) Verschwendung von Rechenzeit beim Warten Nur abwechselnder Zugriff auf kritischen Abschnitt Beispiel für kritische Situation: Prozess 0 ist schnell, Prozess 1 ist langsam (sehr langer nicht-kritischer Abschnitt) Bedingung 4 ist nicht erfüllt! RW-Systemarchitektur Kap. 10

14 Versuch 2 Jetzt 2 gemeinsame Variablen zur Kommunikation:
Prozess 0 schreibt auf ready[0], liest beide Prozess 1 schreibt auf ready[1], liest beide Bedeutung von ready[i] = true: Prozess i will in den kritischen Abschnitt Initialisierung: ready[0] := false; ready[1] := false; /* Prozess 0 */ repeat { while (ready[1] = true) tue nichts; ready[0] := true; /* kritischer Abschnitt */ ready[0] := false; /* nichtkrit. Abschnitt */ } /* Prozess 1 */ repeat { while (ready[0] = true) tue nichts; ready[1] := true; /* kritischer Abschnitt */ ready[1] := false; /* nichtkrit. Abschnitt */ } RW-Systemarchitektur Kap. 10

15 Versuch 2: Analyse Vorteil: Auch nicht-alternierender Zugriff auf kritischen Abschnitt Nachteile: „Busy waiting“ („while (ready[i]  true) tue nichts;”) Wechselseitiger Ausschluss nicht garantiert!! Beispiel für Fehlersituation : ready[0] = ready[1] = false Prozess 0 schließt Schleife („while (ready[1]  true) tue nichts;”) ab, gibt CPU ab Prozess 1 schließt Schleife („while (ready[0]  true) tue nichts;”) ab Jetzt können beide Prozesse ungehindert den kritischen Abschnitt betreten: Prozess 1 betritt kritischen Abschnitt, gibt CPU ab Prozess 0 betritt kritischen Abschnitt RW-Systemarchitektur Kap. 10

16 Versuch 3 Anforderung des kritischen Abschnittes wird vorgezogen, um das gezeigte Problem zu verhindern: /* Prozess 0 */ repeat { ready[0] := true; while (ready[1] = true) tue nichts; /* kritischer Abschnitt */ ready[0] := false; /* nichtkrit. Abschnitt */ } /* Prozess 1 */ repeat { ready[1] := true; while (ready[0] = true) tue nichts; /* kritischer Abschnitt */ ready[1] := false; /* nichtkrit. Abschnitt */ } RW-Systemarchitektur Kap. 10

17 Versuch 3: Analyse Vorteil: Nachteil:
Auch nicht-alternierender Zugriff auf kritischen Abschnitt Wechselseitiger Ausschluss garantiert! Nachteil: „Busy waiting“ („while (ready[i]  true) tue nichts;”) Es kann aber trotzdem ein Problem auftreten: ready[0] = ready[1] = false Prozess 0 setzt ready[0] := true und gibt CPU ab Prozess 1 setzt ready[1] := true Jetzt werden beide Prozesse ihre Schleife „while (ready[i]  true) tue nichts;” nie verlassen! Eine solche Situation nennt man Livelock. RW-Systemarchitektur Kap. 10

18 Wechselseitiger Ausschluss
Ergebnis: Anforderung zu früh ) Livelock Anforderung zu spät ) kein wechselseitiger Ausschluss, “kritischer Wettlauf” (race condition) RW-Systemarchitektur Kap. 10

19 4. Versuch „Nichtstun“ in Schleife wird ersetzt durch zeitweilige Zurücknahme der Anforderung, um es anderen Prozessen zu erlauben, die Ressource zu belegen: /* Prozess 0 */ repeat { ready[0] := true; while (ready[1] = true) { ready[0] := false; /* zufäll.Verzög. */; } /* kritischer Abschnitt */ /* nichtkrit. Abschnitt */ /* Prozess 1 */ repeat { ready[1] := true; while (ready[0] = true) { ready[1] := false; /* zufäll.Verzög. */; } /* kritischer Abschnitt */ /* nichtkrit. Abschnitt */ RW-Systemarchitektur Kap. 10

20 Versuch 4: Analyse Vorteil: Nachteil:
Auch nicht-alternierender Zugriff auf kritischen Abschnitt Wegen zufälliger Verzögerung nur geringe Wahrscheinlichkeit für Deadlock. Nachteil: „Busy waiting“ Deadlock nach wie vor möglich! Unsaubere Lösung! Verhalten ist schlecht vorhersagbar Es gibt Situationen, in denen es nie voran geht oder es für sehr lange Zeit nicht voran geht Nach Beobachtung eines unerwünschten Verhaltens tritt dieses möglicherweise über sehr lange Zeit nicht mehr auf ) kritische Wettläufe (race condition)! RW-Systemarchitektur Kap. 10

21 Versuch 5 3 gemeinsame Variablen: turn, ready[0], ready[1]
Initialisierung: ready[0] := false; ready[1] := false; turn beliebig Variable turn bestimmt, welcher Prozess dran ist. /* Prozess 0 */ repeat { ready[0] := true; turn := 1; while (ready[1] = true && turn = 1) tue nichts; /* kritischer Abschnitt */ ready[0] := false; /* nichtkrit. Abschnitt */ } /* Prozess 1 */ repeat { ready[1] := true; turn := 0; while (ready[0] = true && turn = 0) tue nichts; /* kritischer Abschnitt */ ready[1] := false; /* nichtkrit. Abschnitt */ } RW-Systemarchitektur Kap. 10

22 5. Versuch: Analyse (1) Deadlock: Wechselseitiger Ausschluss:
Kein Deadlock möglich wegen Variable turn! turn kann nicht gleichzeitig 0 und 1 sein. Wechselseitiger Ausschluss: Nur einer von beiden interessiert: der andere darf eintreten, Beide interessiert: der darf eintreten, auf den turn zeigt Nicht-alternierender Zugriff: Möglich, weil ready[i] = false, wenn Prozess i in nicht-kritischem Abschnitt. RW-Systemarchitektur Kap. 10

23 5. Versuch: Analyse (2) Vorteile: Nachteil:
Nicht-alternierender Zugriff auf den kritischen Abschnitt Wechselseitiger Ausschluss garantiert Kein Deadlock Nachteil: Aktives Warten Versuch 5 entspricht Petersons Algorithmus für wechselseitigen Ausschluss (1981). Verallgemeinerbar auf n Prozesse (wesentlich komplizierter!). RW-Systemarchitektur Kap. 10

24 Wechselseitiger Ausschluss in Software – Was haben wir bisher gelernt?
Wechselseitiger Ausschluss ist in Software schwer zu realisieren. Alles was einfacher ist als Petersons Algorithmus ist höchstwahrscheinlich falsch. Beweise des Gegenteils sind durchaus willkommen …  Fehler durch kritische Wettläufe, subtile Fehler Formale Beweise sind unabdingbar! Software-Lösungen für wechselseitigen Ausschluss benötigen aktives Warten. Effizientere Lösungen sind möglich durch Hardware-Unterstützung Ins Betriebssystem integrierte Lösungen RW-Systemarchitektur Kap. 10


Herunterladen ppt "Kapitel 10 Nebenläufigkeit und wechselseitiger Ausschluss"

Ähnliche Präsentationen


Google-Anzeigen