27
Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/10 1

Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Embed Size (px)

Citation preview

Page 1: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Systeme 1

Kapitel 6.1Nebenläufigkeit und wechselseitiger

Ausschluss

WS 2009/10 1

Page 2: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Letzte Vorlesung

• Threads– „leichtgewichtige Prozesse“– Gemeinsamer Adressraum

• Nebenläufigkeit (Threads)– parallele bzw. pseudo-parallele Ausführung– Kontrollprobleme• Wechselseitiger Ausschluss• Deadlocks• Livelocks

– Anforderungen an wechselseitigen AusschlussWS 2009/10 2

Page 3: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Letzte Vorlesung

• Anforderungen an wechselseitigen Ausschluss– Softwarelösungen• Versuche 1 - 5

WS 2009/10 3

Busy Waiting

Wechselseitiger Ausschluss garantiert

Nicht-alternierender Zugriff auf kritischen Abschnitt möglich

Versuch 1

Versuch 2

Versuch 3

Versuch 4

Versuch 5

Page 4: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss in Hardware

• Zur Erinnerung Versuch 2 als Softwarelösung

– Warum scheiterte dieser Versuch? – Weil Testen und Setzen von Flags nicht in einem einzigen

Schritt durchführbar:• Prozesswechsel zwischen Testen und Setzen ist möglich.

WS 2009/10 4

/* Prozess 0 */wiederhole {

solange (flag[1] = true) tue nichts;flag[0] := true;/* kritischer Abschnitt */flag[0] := false;/* nichtkrit. Abschnitt */

}

/* Prozess 1 */wiederhole {

solange (flag[0] = true) tue nichts;flag[1] := true;/* kritischer Abschnitt */Flag[1] := false;/* nichtkrit. Abschnitt */

}

Page 5: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss in Hardware

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

WS 2009/10 5

Page 6: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss in Hardware

• Befehl TSL RX, LOCK mit Speicheradresse LOCK und Register RX hat folgende Wirkung:– RX = Speicher[LOCK]; Speicher[LOCK] := 1– Ein Befehl, d.h. 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? (CMP = compare)JNE enter_region // Wenn Lock schon gesetzt war -> Schleife

(JNE = jump if not equal)... // Fortfahren und Betreten des krit. Abschnitts

• Prozesse, die den kritischen Abschnitt verlassen, führen folgenden Befehl aus: STOREI LOCK, #0 // Speicher[LOCK] := 0 (STOREI = store immediate)

WS 2009/10 6

Page 7: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss im Betriebssystem

• Folgerung:– Um aktives Warten zu verhindern, muss wechselseitiger Ausschluss ins

Betriebssystem integriert werden! – Idee: Statt aktiv zu warten, blockiere 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 (sofern ein solcher Prozess vorhanden ist).

– Neuer Systemaufruf wakeup(lock)– Parameter lock wird nur gebraucht, um Aufrufe für den gleichen

kritischen Abschnitt einander zuzuordnen.– Eine Warteschlange pro kritischem Abschnitt

WS 2009/10 7

Page 8: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Mutex• Mutex = Mutual Exclusion• Vor dem Eintritt in einen kritischen Abschnitt wird die

Funktion mutex_lock(lock) aufgerufen.

• testset(lock) führt atomare TSL-Operation aus; liefert true gdw. Lockvariable vorher 0 war.

WS 2009/10 8

function mutex_lock(lock){

solange (testset(lock) = false){

sleep(lock);}return;

}

Page 9: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Mutex• 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 Queue bereit (aber nicht notwendigerweise aktiv -> Scheduler-Algorithmus!).

• Die Variable lock heißt Mutexvariable bzw. kurz Mutex.WS 2009/10 9

function mutex_unlock(lock){

unset(lock); // lock wird freigegebenwakeup(lock);return;

}

Page 10: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

Typisches Problem bei nebenläufigen Prozessen:– 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.

WS 2009/10 10

Page 11: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

• Lösungsansatz:– Gemeinsame Variable count für die Anzahl der

Elemente im Puffer– Initialer Wert 0– sleep() und wakeup()– Anfangs schlafen die Konsumenten (Puffer ist

leer).

WS 2009/10 11

Page 12: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

WS 2009/10 12

Prozedur producer{ ... wiederhole

{ item = produce_item(); //produziere nächstes Objekt wenn (count = MAX_BUFFER) //schlafe, wenn Puffer

sleep(producer); //voll

insert_item(item) // Einfügen in Puffer count = count + 1; wenn (count = 1) // wenn Puffer vorher leer:

wakeup(consumer); // wecke Konsumenten}

}

Page 13: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

WS 2009/10 13

Prozedur consumer{ ... wiederhole

{ wenn (count = 0) // schlafe, wenn Puffer

Sleep(consumer); // leer item = remove_item(); // Entferne aus Puffer count = count -1;

wenn (count = MAX_BUFFER – 1) // wenn Puffer vollwakeup(producer); // wecke Produzenten

consume_item(item); // konsumiere Objekt}

}

Ist diese Lösung korrekt???

Page 14: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

• Mögliche Probleme:1) Zwei Konsumenten: 1 Element im Puffer

• Konsument 1 entnimmt Element und wird unterbrochen bevor er count auf 0 setzen kann.

• Konsument 2 wird aktiv aber der Puffer ist leer! (count immer noch 1) Fehler!

2) Zwei Konsumenten: Puffer ist voll. • count == MAX_BUFFER• Konsument 1 entnimmt Element und führt count = count–1; aus und

wird dann unterbrochen (count == MAX_BUFFER-1).• Konsument 2 wird aktiv, entnimmt ein Element und reduziert count.• Problem: Produzent wird nie mehr geweckt, da Bedingung

wenn (count = MAX_BUFFER – 1)nie mehr erfüllt wird!

WS 2009/10 14

Page 15: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

• Ein Produzent und ein Konsument– Konsument gibt Prozessor ab nach

wenn(count = 0)

wenn Puffer leer ist– Dann fügt der Produzent ein Objekt ein, count = 1.– Aufwecken des Konsumenten geht verloren, da er noch gar

nicht schläft. – Nach nächstem Prozesswechsel: Konsument schläft für immer.– Wenn Puffer voll wird, schläft auch der Produzent für immer.

Deadlock– Problem:

wenn (count = 0) sleep(consumer)

ist keine atomare Operation!WS 2009/10 15

Page 16: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem

• Die elegante Lösung des Produzenten-Konsumenten Problems ist die Nutzung eines Semaphor.

• Dijkstra (1965)• Entwickelt zur Synchronisation von Prozessen.• Konzept:– Integer-Variable mit drei Operationen:

• Initialisierung mit nicht-negativen Wert• down() Operation• up() Operation

WS 2009/10 16

Page 17: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss mit Semaphoren

• Voraussetzungen:– Es existiert ein Semaphor s.– countS ist auf 1 initialisiert.– n Prozesse sind gestartet, konkurrieren um

kritischen Abschnitt.

WS 2009/10 17

/* Prozess i */wiederhole{

down(s);/* kritischer Abschnitt */up(s);/* nichtkritischer Abschnitt */

}

Page 18: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss mit Semaphoren

• Beispiel:– Semaphor wird mit 1 initialisiert.– Prozess 1 geht in kritischen Abschnitt:

• down(s) -> Semaphor-Zähler wird 0– Prozess 2 will in den kritischen Abschnitt:

• down(s) -> Semaphor-Zähler wird -1– Prozess 2 wird blockiert und in die Warteschlange

eingefügt. – Prozess 3 will in den kritischen Abschnitt:

• down(s) -> Semaphor-Zähler wird -2• Prozess 3 wird blockiert und in die Warteschlange eingefügt.

– Prozess 1 verlässt kritischen Abschnitt:• up(s) -> Semaphor-Zähler wird -1• Zähler <= 0, d.h. ein Prozess wird der Warteschlange entnommen

und wird bereit.WS 2009/10 18

Page 19: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Wechselseitiger Ausschluss mit Semaphoren

• Auf 1 initialisierte Semaphore heißen binäre Semaphore.

• Behandlung mehrfach nutzbarer Ressourcen (m-fach) ist möglich:– durch Initialisierung countS = m.

• 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.WS 2009/10 19

Page 20: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem mit Semaphoren

WS 2009/10 20

Prozedur producer{ ... wiederhole

{ item = produce_item(); //produziere nächstes Objekt down(empty); down(mutex); insert_item(item); // Einfügen in Puffer up(mutex); up(full);}

}

semaphore mutex; countmutex = 1;

// mutex für kritische Abschnitte

semaphore empty; countempty = MAX_BUFFER;

// zählt freie Plätze

semaphore full; countfull = 0;

// zählt belegte Plätze

Page 21: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem mit Semaphoren

WS 2009/10 21

Prozedur consumer{ ... wiederhole

{ down(full); down(mutex); item = remove_item(); // Entferne aus Puffer up(mutex); up(empty); consume_item(item); // konsumiere Objekt}

}

Frage:– Funktioniert das immer noch, wenn in Prozedur consumer• up(mutex) und up(empty) vertauscht werden?• down(full) und down(mutex) vertauscht werden?

Page 22: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Das Produzenten-Konsumenten Problem mit Semaphoren

• Frage: Funktioniert das immer noch, wenn in Prozedur consumer– up(mutex) und up(empty) vertauscht werden?– down(full) und down(mutex) vertauscht werden?

• Angenommen der Puffer ist leer:– down(mutex), down(full)• Konsument blockiert, da es keine „vollen Plätze“ gibt.• Produzenten können aber nicht den Puffer füllen, da

sie alle bei down(mutex) hängen bleiben.• Irgendwann schlafen alle -> Deadlock!

WS 2009/10 22

Page 23: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Implementierung von Semaphoren: Versuch 1

WS 2009/10 23

down(semaphore s) { mutex_lock(lockS); countS = countS - 1; wenn (countS < 0) { setze diesen Prozess in queueS; blockiere den Prozess und führe unmittelbar vor Abgabe des Prozessors noch mutex_unlock(lockS) aus } sonst 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); }

k.A.

k.A.

Page 24: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

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, weil Mutexe alleine schon reichen, um wechselseitigen Ausschluss zu garantieren!

Zwei Queues:• Liste von Prozessen, die auf Freigabe des Mutex warten.• Liste von Prozessen, die auf Erhöhung der Semaphor-

Variable warten.

WS 2009/10 24

Page 25: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Implementierung von Semaphoren: Versuch 2

WS 2009/10 25

down(semaphore s) { solange (testset(lockS) = false) tue nichts; countS = countS - 1; wenn (countS < 0) { setze diesen Prozess in queueS; blockiere den Prozess und führe unmittelbar vor Abgabe des Prozessors noch lockS = 0 aus } sonst lockS = 0 }

up(semaphore s) { solange (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; }

k.A.

k.A.

Page 26: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

Implementierung von Semaphoren: Versuch 2

• Analyse:– aktives Warten (solange(...) tue nichts;)!

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

WS 2009/10 26

Page 27: Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss WS 2009/101

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.

WS 2009/10 27