Newest Viewed Downloaded

Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger AusschlussWS 2009/10 *

Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss

WS 2009/10 *

Letzte Vorlesung

Threads „leichtgewichtige Prozesse“ Gemeinsamer Adressraum Nebenläufigkeit (Threads) parallele bzw. pseudo-parallele Ausführung Kontrollprobleme Wechselseitiger Ausschluss Deadlocks Livelocks Anforderungen an wechselseitigen Ausschluss WS 2009/10 *

Letzte Vorlesung

Anforderungen an wechselseitigen Ausschluss Softwarelösungen Versuche 1 - 5 WS 2009/10 * Busy Waiting Wechselseitiger Ausschluss garantiert Nicht-alternierender Zugriff auf kritischen Abschnitt möglich Versuch 1 Versuch 2 Versuch 3 Versuch 4 Versuch 5

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

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 *

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 Lock CMP 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 *

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 *

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 * function mutex_lock(lock) { solange (testset(lock) = false) { sleep(lock); } return; }

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 * function mutex_unlock(lock) { unset(lock); // lock wird freigegeben wakeup(lock); return; }

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 *

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 *

Das Produzenten-Konsumenten Problem

WS 2009/10 * 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 } }

Das Produzenten-Konsumenten Problem

WS 2009/10 * 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 voll wakeup(producer); // wecke Produzenten consume_item(item); // konsumiere Objekt } } Ist diese Lösung korrekt???

Das Produzenten-Konsumenten Problem

Mögliche Probleme: 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! 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 *

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 *

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 *

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 * /* Prozess i */ wiederhole { down(s); /* kritischer Abschnitt */ up(s); /* nichtkritischer Abschnitt */ }

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 *

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 *

Das Produzenten-Konsumenten Problem mit Semaphoren

WS 2009/10 * 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

Showing 1 - 20 of 27 items Details

Name: 
Folien Kapitel6_1
Author: 
derDaywalker
Company: 
N/A
Description: 
Systeme 1 Kapitel 6.1 Nebenläufigkeit und wechselseitiger AusschlussWS 2009/10 *
Tags: 
lock | 2009 | mutex | down | puffer | prozess | count | konsumenten
Created: 
10/29/2009 2:16:53 AM
Slides: 
27
Views: 
27
Downloads: 
0
Rating: 
0


Comment



Share this presentation
|

Comments

Share this presentation:

|
Sitemap