Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

RW-SystemarchitekturKap. 10 1 10.2 Wechselseitiger Ausschluss in Hardware Zur Erinnerung: 2. Versuch in Software /* Prozess 0 */ repeat { while (ready[1]

Ähnliche Präsentationen


Präsentation zum Thema: "RW-SystemarchitekturKap. 10 1 10.2 Wechselseitiger Ausschluss in Hardware Zur Erinnerung: 2. Versuch in Software /* Prozess 0 */ repeat { while (ready[1]"—  Präsentation transkript:

1 RW-SystemarchitekturKap 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

2 RW-SystemarchitekturKap 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.

3 RW-SystemarchitekturKap 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

4 RW-SystemarchitekturKap 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.)

5 RW-SystemarchitekturKap 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.

6 RW-SystemarchitekturKap 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; }

7 RW-SystemarchitekturKap 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; }

8 RW-SystemarchitekturKap 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.

9 RW-SystemarchitekturKap 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...

10 RW-SystemarchitekturKap 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 }

11 RW-SystemarchitekturKap 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 }

12 RW-SystemarchitekturKap 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???

13 RW-SystemarchitekturKap 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!

14 RW-SystemarchitekturKap 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.

15 RW-SystemarchitekturKap 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.

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

17 RW-SystemarchitekturKap Semaphore Behandlung mehrfach nutzbarer Ressourcen (m-fach nutzbar mit m 2 N ) ist möglich (zählendes Semaphor): –durch Initialisierung count s = m 2 N. Interpretation von count s : –Falls count s ¸ 0: count s 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 count s < 0: |count s | ist die Anzahl der wartenden Prozesse in queue s. Ein zählendes Semaphor s hat 3 Komponenten: –Integer-Variable count s –Warteschlange queue s –Lock-Variable lock s (für Implementierung, siehe später)

18 RW-SystemarchitekturKap Produzenten/Konsumenten-Problem mit Semaphoren 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); } semaphore mutex; count mutex = 1; // mutex für kritische Abschnitte semaphore non_full; count non_full = MAX_BUFFER; // zählt freie Plätze semaphore non_empty; count non_empty = 0; // zählt belegte Plätze

19 RW-SystemarchitekturKap 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?

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

21 RW-SystemarchitekturKap 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

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

23 RW-SystemarchitekturKap 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

24 RW-SystemarchitekturKap 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


Herunterladen ppt "RW-SystemarchitekturKap. 10 1 10.2 Wechselseitiger Ausschluss in Hardware Zur Erinnerung: 2. Versuch in Software /* Prozess 0 */ repeat { while (ready[1]"

Ähnliche Präsentationen


Google-Anzeigen