rw-systemarchitekturkap. 10 1 10.2 wechselseitiger ausschluss in hardware zur erinnerung: 2. versuch...

23
RW-Systemarchitekt ur Kap. 10 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

Upload: leonore-zahniser

Post on 05-Apr-2015

105 views

Category:

Documents


2 download

TRANSCRIPT

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

RW-Systemarchitektur Kap. 101

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

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

RW-Systemarchitektur Kap. 102

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.

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

RW-Systemarchitektur Kap. 103

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 LockCMP 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

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

RW-Systemarchitektur Kap. 104

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.)

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

RW-Systemarchitektur Kap. 105

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.

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

RW-Systemarchitektur Kap. 106

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

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

RW-Systemarchitektur Kap. 107

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

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

RW-Systemarchitektur Kap. 108

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.

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

RW-Systemarchitektur Kap. 109

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

...

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

RW-Systemarchitektur Kap. 1010

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 } }

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

RW-Systemarchitektur Kap. 1012

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???

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

RW-Systemarchitektur Kap. 1013

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!

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

RW-Systemarchitektur Kap. 1014

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.

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

RW-Systemarchitektur Kap. 1015

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.

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

RW-Systemarchitektur Kap. 1016

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. counts ist auf 1 initialisiert– n Prozesse sind gestartet, konkurrieren um kritischen Abschnitt.

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

RW-Systemarchitektur Kap. 1017

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)

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

RW-Systemarchitektur Kap. 1018

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; countmutex = 1; // mutex für kritische Abschnittesemaphore non_full; countnon_full = MAX_BUFFER; // zählt freie Plätzesemaphore non_empty; countnon_empty = 0; // zählt belegte Plätze

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

RW-Systemarchitektur Kap. 1019

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?

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

RW-Systemarchitektur Kap. 1020

Implementierung von Semaphoren mit mutexen: Versuch 1

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); }

• Systemaufrufe down und up

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

RW-Systemarchitektur Kap. 1021

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

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

RW-Systemarchitektur Kap. 1022

Implementierung von Semaphoren: Versuch 2

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

• Systemaufrufe down und up

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

RW-Systemarchitektur Kap. 1023

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

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

RW-Systemarchitektur Kap. 1024

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