Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

10.2 Wechselseitiger Ausschluss in Hardware

Ähnliche Präsentationen


Präsentation zum Thema: "10.2 Wechselseitiger Ausschluss in Hardware"—  Präsentation transkript:

1 10.2 Wechselseitiger Ausschluss in Hardware
Zur Erinnerung: 2. Versuch in Software /* 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 */ } Warum scheiterte dieser Versuch? Weil Testen und Setzen von ready[] nicht in einem einzigen, unteilbaren Schritt durchführbar: ) Prozesswechsel zwischen Testen und Setzen ist möglich RW-Systemarchitektur Kap. 10

2 Wechselseitiger Ausschluss in Hardware (2)
Neues Konzept: Einführung atomarer Operationen. Hardware garantiert atomare Ausführung. Testen und Setzen zusammen bilden eine atomare Operation: Definiere neuen Befehl TSL: Test and Set Lock Da TSL ein einziger Befehl ist, kann ein Prozesswechsel nicht zwischen Testen und Setzen erfolgen (nicht “mitten im Befehl”) Für jeden kritischen Bereich eine Sperrvariable mit Wert = 0 für ungesperrt und Wert ungleich 0 für gesperrt. RW-Systemarchitektur Kap. 10

3 Wechselseitiger Ausschluss in Hardware (3)
Befehl TSL RX, LOCK mit Speicheradresse LOCK und Register RX hat folgende Wirkung: RX = Speicher[LOCK]; Speicher[LOCK] := 1 Ein Befehl ) atomare Ausführung Prozesse, die Zugriff auf den kritischen Abschnitt erhalten wollen, führen folgende Befehle aus: enter_region: TSL RX, LOCK // kopiere Lock-Variable und setze Lock CMP RX, #0 // War Lock-Variable = 0? Ungesperrt? JNE enter_region // Wenn Lock schon gesetzt war ) Schleife ... // Fortfahren und Betreten des krit. Abschnitts Prozesse, die den kritischen Abschnitt verlassen, führen folgenden Befehl aus: STOREI LOCK, #0 // Speicher[LOCK] := 0 RW-Systemarchitektur Kap. 10

4 Wechselseitiger Ausschluss in Hardware - Analyse
Vorteil: Nicht-alternierender Zugriff auf den kritischen Abschnitt Wechselseitiger Ausschluss garantiert Kein Deadlock Nachteil: Aktives Warten genau wie bei Softwarelösung! Weiterer Nachteil sowohl für Petersons Algorithmus als auch für Hardware-Lösung: Bei festen Prioritäten von Prozessen und Präemption können diese Lösungen trotzdem zu Livelocks führen. Szenario: Prozess 0 hat höhere Priorität, ist aber (z.B. wegen I/O-Operation) blockiert. Prozess 1 betritt kritischen Abschnitt. Prozess 0 wird wieder rechenbereit, erhält Prozessor wegen höherer Priorität Wenn Prozess 0 in den kritischen Abschnitt will, betritt er die Schleife für aktives Warten ) Livelock!!! Dies heißt Prioritätsinversion Problem dahinter: Kombination von präemptivem Scheduling mit nichtpräemtiver Bedingung (kritischer Bereich, Ressource etc.) RW-Systemarchitektur Kap. 10

5 10.3 Wechselseitiger Ausschluss, ins Betriebssystem integriert
Folgerung: Um aktives Warten zu verhindern, muss wechselseitiger Ausschluss ins Betriebssystem integriert werden! Idee: Statt aktiv zu warten, blockieren Prozesse einfach! ) neuer Systemaufruf sleep(lock) Nach Verlassen des kritischen Abschnitts weckt der verlassende Prozess einen anderen Prozess auf, der auf Erlaubnis wartet, den kritischen Abschnitt zu betreten (wenn ein solcher Prozess vorhanden ist) ) neuer Systemaufruf wakeup(lock) Variable lock wird eindeutig einem kritischen Abschnitt zugeordnet. lock = 0 heißt nicht gesperrt. Alles andere heißt gesperrt. RW-Systemarchitektur Kap. 10

6 Mutexe Vor Eintritt in kritischen Abschnitt wird Funktion mutex_lock(lock) aufgerufen: testset(lock) führt TSL-Befehl aus und liefert true gdw. Lock-Variable vorher 0, d.h. ungesperrt war. function mutex_lock(int lock) { if (testset(lock) = false) sleep(lock); return; } RW-Systemarchitektur Kap. 10

7 Mutexe Nach Verlassen des kritischen Abschnitts wird mutex_unlock(lock) aufgerufen: Es muss eine Warteschlange für Prozesse geben, die auf lock warten. Nach wakeup(lock) wird der erste Prozess in der Warteschlange bereit (aber nicht notwendigerweise aktiv). Die Variable lock heißt Mutexvariable bzw. kurz Mutex. Sie wird üblicherweise vom Betriebssystem verwaltet (im Adressraum des Betriebssystems). function mutex_unlock(int lock) { lock = 0; wakeup(lock); return; } RW-Systemarchitektur Kap. 10

8 Das Produzenten/Konsumenten-Problem mit mutex und Zählvariable (1)
Typisches Problem bei nebenläufigen Prozesse: Gemeinsamer Puffer Einige Prozesse schreiben in den Puffer (“Produzenten”) Einige Prozesse lesen aus dem Puffer (“Konsumenten”) Prozedur insert_item schreibt Objekt in Puffer. Prozedur remove_item entfernt Objekt aus Puffer. Puffergröße ist beschränkt und Puffer kann leer sein. Wenn Puffer voll ist, dann sollten Produzenten nicht einfügen. Aus Effizienzgründen: Blockieren der Produzenten, die einfügen wollen. Wenn Puffer leer ist, sollten Konsumenten nichts entfernen. Aus Effizienzgründen: Blockieren der Konsumenten, die entfernen wollen. RW-Systemarchitektur Kap. 10

9 Weiteres Beispiel für Interaktion verschiedener Prozesse: Das Produzenten/Konsumenten-Problem (2)
Lösung mit gemeinsamer Variable count für Anzahl der Elemente im Puffer (initialisiert durch 0) sleep und wakeup auf zwei Mutexen p und c Prozesse, die auf p warten, wollen einfügen, Prozesse, die auf c warten, wollen konsumieren. Anfangs schläft Konsument ... RW-Systemarchitektur Kap. 10

10 Weiteres Beispiel für Interaktion verschiedener Prozesse: Das Produzenten/Konsumenten-Problem (2)
Prozedur producer { repeat item = produce_item(); // produziere nächstes // Objekt if (count = MAX_BUFFER) // schlafe, wenn Puffer voll sleep(p); insert_item(item); // Einfügen in Puffer count = count + 1; if (count = 1) // wenn Puffer vorher leer: wakeup(c); // wecke Konsumenten } RW-Systemarchitektur Kap. 10

11 Weiteres Beispiel für Interaktion verschiedener Prozesse: Das Produzenten/Konsumenten-Problem (2)
Prozedur producer { repeat item = produce_item(); // produziere nächstes // Objekt if (count = MAX_BUFFER) // schlafe, wenn Puffer voll sleep(p); insert_item(item); // Einfügen in Puffer count = count + 1; if (count = 1) // wenn Puffer vorher leer: wakeup(c); // wecke Konsumenten } RW-Systemarchitektur Kap. 10

12 Ist diese Lösung korrekt???
Weiteres Beispiel für Interaktion verschiedener Prozesse: Das Produzenten/Konsumenten-Problem (3) Prozedur consumer { repeat if (count = 0) // schlafe, wenn Puffer sleep(consumer); // leer item = remove_item(); // Entfernen aus Puffer count = count - 1; if (count = MAX_BUFFER - 1) // wenn Puffer vorher // voll wakeup(producer); // wecke Konsumenten consume_item(item); // konsumiere Objekt } Ist diese Lösung korrekt??? RW-Systemarchitektur Kap. 10

13 Weiteres Beispiel für Interaktion verschiedener Prozesse: Das Produzenten/Konsumenten-Problem (4)
Die “Lösung” ist falsch! Problem: “if (count = 0) sleep(c)“ ist keine atomare Operation. Fehlersituation: concumer gibt Prozessor ab nach “if (count = 0)”, wenn Puffer leer ist Dann fügt producer Objekt ein und erhöht count auf 1 Aufwecken von consumer geht verloren, da er noch gar nicht schläft. Nach nächstem Prozesswechsel: consumer schläft für immer. Wenn Puffer voll wird, schläft auch producer für immer. ) Deadlock! Erneut: Subtile Fehler, Beweise nötig! RW-Systemarchitektur Kap. 10

14 Elegante Lösung des Produzenten/Konsumenten-Problems
Unsere Lösung benutzt zählende Semaphore, Dijkstra 1965 Entwickelt zur Synchronisation von Prozessen. Konzept: Integer-Variable mit 3 Operationen: Initialisierung mit nicht-negativem Wert down-Operation Verringere Wert um 1 Wenn Wert < 0, blockiere aufrufenden Prozess. up-Operation Erhöhe Wert um 1 Wenn Wert >= 0, wecke einen der blockierten Prozesse auf (wird bereit). Wichtig: up und down müssen atomare Operationen sein. Garantiert durch Betriebssystem und Hardware. RW-Systemarchitektur Kap. 10

15 Binäre Semaphore Semaphore, die exklusiven Zutritt zu einem kritischen Abschnitt gewähren, heißen binäre Semaphoren. Zustand 0 heißt gesperrt, Zustand 1 heißt nicht gesperrt. RW-Systemarchitektur Kap. 10

16 Wechselseitiger Ausschluss mit Semaphoren (1)
Voraussetzungen: Ein binäres Semaphor s, d.h. counts ist auf 1 initialisiert n Prozesse sind gestartet, konkurrieren um kritischen Abschnitt. /* Prozess i */ repeat { down(s); /* kritischer Abschnitt */; up(s); /* nichtkrit. Abschnitt */; } Erster Prozess betritt kritischen Abschnitt. Andere Prozesse müssen warten. Bei Verlassen des kritischen Abschnitts wird Semaphor-Variable erhöht. RW-Systemarchitektur Kap. 10

17 Semaphore Behandlung mehrfach nutzbarer Ressourcen (m-fach nutzbar mit m 2 N) ist möglich (zählendes Semaphor): durch Initialisierung counts = m 2 N. Interpretation von counts: Falls counts ¸ 0: counts gibt die Anzahl der Prozesse an, die down(s) ausführen können ohne zu blockieren (wenn nicht zwischenzeitlich up(s) ausgeführt wird). Falls counts < 0: |counts| ist die Anzahl der wartenden Prozesse in queues. Ein zählendes Semaphor s hat 3 Komponenten: Integer-Variable counts Warteschlange queues Lock-Variable locks (für Implementierung, siehe später) RW-Systemarchitektur Kap. 10

18 Produzenten/Konsumenten-Problem mit Semaphoren
semaphore mutex; countmutex = 1; // mutex für kritische Abschnitte semaphore non_full; countnon_full = MAX_BUFFER; // zählt freie Plätze semaphore non_empty; countnon_empty = 0; // zählt belegte Plätze Prozedur producer { repeat item = produce_item(); // produziere nächstes Objekt down(non_full); down(mutex); insert_item(item); // Einfügen in Puffer up(mutex); up(non_empty); } RW-Systemarchitektur Kap. 10

19 Produzenten/Konsumenten-Problem mit Semaphoren
Prozedur consumer { repeat down(non_empty); down(mutex); item = remove_item(); // Entfernen aus Puffer up(mutex); up(non_full); consume_item(item); // konsumiere Objekt } Frage:Funktioniert das immer noch, wenn in Prozedur consumer up(mutex) und up(non_full) vertauscht werden? down(non_empty) und down(mutex) vertauscht werden? RW-Systemarchitektur Kap. 10

20 Implementierung von Semaphoren mit mutexen: Versuch 1
Systemaufrufe down und up down(semaphore s) { mutex_lock(locks); counts = counts - 1; if (counts < 0) setze diesen Prozess in queues; blockiere den Prozess und führe unmittelbar vor Abgabe des Prozessors noch mutex_unlock(locks) aus } else mutex_unlock(locks); up(semaphore s) { mutex_lock(locks); counts = counts + 1; if (counts > 0) entferne einen Prozess P aus queues; Schreibe Prozess P in Liste der bereiten Prozesse } mutex_unlock(locks); RW-Systemarchitektur Kap. 10

21 Implementierung von Semaphoren: Versuch 1
Analyse: down und up sind nicht wirklich atomar, aber trotzdem stören sich verschiedene Aufrufe von down und up nicht aufgrund des mutex. Zumindest für binäre Semaphore ist Verwendung von mutexen in Semaphoraufrufen etwas aufwändig! Zwei Queues: Liste von Prozessen, die auf Freigabe des mutex warten Liste von Prozessen, die auf Erhöhung der Semaphor-Variable warten RW-Systemarchitektur Kap. 10

22 Implementierung von Semaphoren: Versuch 2
Systemaufrufe down und up down(semaphore s) { while (testset(locks) = false) tue nichts; counts = counts - 1; if (counts < 0) setze diesen Prozess in queues; blockiere den Prozess und führe unmittelbar vor Abgabe des Prozessors noch locks = 0 aus } else locks = 0 up(semaphore s) { while (testset(locks) = false) tue nichts; counts = counts + 1; if (counts <= 0) entferne einen Prozess P aus queues; Schreibe Prozess P in Liste der bereiten Prozesse } locks = 0; RW-Systemarchitektur Kap. 10

23 Implementierung von Semaphoren: Versuch 2
Analyse der Implementierung: aktives Warten! nicht so gravierend: beschränkt auf up und down up und down sind relativ kurz down und up sind nicht wirklich atomar, aber trotzdem stören sich verschiedene Aufrufe von down und up nicht aufgrund des busy waitings. Semaphoren blockieren Prozesse ) keine CPU-Zeit für wartende Prozesse Unterbinden von Unterbrechungen nicht nötig. Implementierung auch für Multiprozessoren geeignet. Für Benutzer sind nur abstrakte Semaphoren sichtbar, keine Implementierungsdetails RW-Systemarchitektur Kap. 10

24 Zusammenfassung CPU (einzelne CPU oder Multiprozessor) wird von mehreren Prozessen geteilt. Verwaltung gemeinsamer Ressourcen bei Multiprogramming ist nicht trivial. Subtile Fehler möglich, formale Beweise nötig Konzepte für wechselseitigen Ausschluss, Produzenten/Konsumenten-Problem RW-Systemarchitektur Kap. 10


Herunterladen ppt "10.2 Wechselseitiger Ausschluss in Hardware"

Ähnliche Präsentationen


Google-Anzeigen