10.10.2013 Aufrufe

4 auf 1 - Betriebssysteme und verteilte Systeme

4 auf 1 - Betriebssysteme und verteilte Systeme

4 auf 1 - Betriebssysteme und verteilte Systeme

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Wiederholung<br />

➥ Prozeßinteraktion<br />

➥ Synchronisation, Kommunikation<br />

➥ Wechselseitiger Ausschluß<br />

➥ nur jeweils ein Prozeß darf im kritischen Abschnitt sein<br />

➥ kritischer Abschnitt: Zugriff <strong>auf</strong> gemeinsame Ressourcen<br />

➥ Lösungsansätze:<br />

<strong>Betriebssysteme</strong> I<br />

WS 2004/2005<br />

16.11.04<br />

Roland Wismüller, Univ. Siegen<br />

roland.wismueller@uni-siegen.de<br />

Tel.: 0271/740-4050, Büro: H-B 8404<br />

c○2004, Roland Wismüller 05-1<br />

➥ Sperren der Interrupts (nur im BS, Einprozessorsysteme)<br />

➥ Sperrvariable: Peterson-Algorithmus<br />

➥ mit Hardware-Unterstützung: Read-Modify-Write<br />

➥ Nachteil: Aktives Warten (Effizienz, Verklemmungsgefahr)<br />

c○2004, Roland Wismüller 05-2<br />

Wiederholung ...<br />

➥ Semaphore: Zähler <strong>und</strong> Prozeßwarteschlange<br />

➥ P(): herunterzählen, ggf. blockieren<br />

➥ V(): hochzählen, ggf. blockierten Prozeß wecken<br />

➥ Atomare Operationen (im BS realisiert)<br />

➥ Wechselseitiger Ausschluß mit Semaphoren:<br />

Prozeß 0 Prozeß 1<br />

P(Mutex); P(Mutex);<br />

// kritischer Abschnitt // kritischer Abschnitt<br />

V(Mutex); V(Mutex);<br />

➥ Semaphore auch für allgemeinere Synchronisation nutzbar<br />

➥ Beispiel: Erzeuger/Verbraucher-Problem<br />

c○2004, Roland Wismüller 05-3<br />

<strong>Betriebssysteme</strong> I<br />

WS 2004/2005<br />

3 Prozeßinteraktion<br />

3.1 Synchronisation<br />

c○2004, Roland Wismüller 05-4


3.1 Synchronisation<br />

Heute:<br />

➥ Klassische Synchronisationsprobleme<br />

➥ Leser/Schreiber-Problem<br />

➥ Problem des schlafenden Friseurs<br />

➥ Monitore<br />

➥ Synchronisation mit PThreads<br />

➥ Barrieren<br />

➥ Tanenbaum 2.4.2, 2.4.3, 2.3.7<br />

➥ Stallings 5.4.4, 5.5<br />

c○2004, Roland Wismüller 05-5<br />

3.1.5 Klassische Synchronisationsprobleme<br />

Das Leser/Schreiber-Problem<br />

➥ Gemeinsamer Datenbereich mehrerer Prozesse<br />

➥ Zwei Klassen von Prozessen (bzw. Zugriffen)<br />

➥ Leser (Reader)<br />

➥ dürfen gleichzeitig mit anderen Lesern zugreifen<br />

➥ Schreiber (Writer)<br />

➥ stehen unter wechselseitigem Ausschluß,<br />

auch mit Lesern<br />

➥ verhindert Lesen von inkonsistenten Daten<br />

➥ Typisches Problem in Datenbank-<strong>Systeme</strong>n<br />

c○2004, Roland Wismüller 05-6<br />

3.1.5 Klassische Synchronisationsprobleme ...<br />

Realisierung des Leser-Schreiber-Problems<br />

Leser<br />

while (true) {<br />

}<br />

P(mutex);<br />

rc++;<br />

if (rc == 1)<br />

P(db);<br />

V(mutex);<br />

readDataBase();<br />

P(mutex);<br />

rc−−;<br />

if (rc == 0)<br />

V(db);<br />

V(mutex);<br />

UseData();<br />

3.1.5 Klassische Synchronisationsprobleme ...<br />

Eigenschaft der skizzierten Lösung<br />

➥ Die Synchronisation ist unfair:<br />

Leser haben Priorität vor Schreibern<br />

➥ Schreiber kann verhungern<br />

Leser 1<br />

Leser 2<br />

➥ Mögliche Lösung:<br />

rc=1 rc=1 rc=2<br />

Semaphore <strong>und</strong><br />

gemeinsame Variable<br />

int rc=0; // Anzahl Leser<br />

Semaphor db; // Schützt Datenbank<br />

Semaphor mutex;<br />

Schreiber<br />

while(true) {<br />

CreateData();<br />

P(db);<br />

writeDataBase();<br />

V(db);<br />

}<br />

c○2004, Roland Wismüller 05-11<br />

rc=1<br />

rc=2<br />

rc=2 rc=1 rc=2 rc=1<br />

➥ neue Leser blockieren, wenn ein Schreiber wartet<br />

c○2004, Roland Wismüller 05-17<br />

...


3.1.5 Klassische Synchronisationsprobleme ...<br />

Das Problem des schlafenden Friseurs<br />

➥ Friseursalon:<br />

3.1.5 Klassische Synchronisationsprobleme ...<br />

Lösung für das Problem des schlafenden Friseurs<br />

int waiting = 0;<br />

Semaphor mutex = 1;<br />

Semaphor customers = 0;<br />

Semaphor barbers = 0;<br />

K<strong>und</strong>e<br />

➥ ein Friseur, ein Friseurstuhl, N Stühle zum Warten<br />

➥ Falls kein K<strong>und</strong>e zu bedienen: Friseur schläft<br />

➥ K<strong>und</strong>e muß Friseur ggf. wecken<br />

➥ Falls Friseur schon einen K<strong>und</strong>en bedient:<br />

➥ weitere K<strong>und</strong>en setzen sich, falls Stuhl frei<br />

➥ falls kein Stuhl frei: Laden verlassen<br />

➥ Gesucht: Synchronisation ohne Race Conditions<br />

c○2004, Roland Wismüller 05-18<br />

Gemeinsame Variable <strong>und</strong> Semaphore<br />

P(mutex)<br />

if (waiting < N) {<br />

waiting++;<br />

V(customers);<br />

V(mutex);<br />

P(barbers);<br />

getHaircut();<br />

} else {<br />

V(mutex);<br />

}<br />

Anzahl wartender K<strong>und</strong>en<br />

für wechselseitigen Ausschluß<br />

Anzahl wartender K<strong>und</strong>en<br />

Anzahl wartender Friseure<br />

Friseur<br />

while (true) {<br />

P(customers);<br />

P(mutex);<br />

waiting−−;<br />

V(barbers);<br />

V(mutex);<br />

cutHair();<br />

}<br />

c○2004, Roland Wismüller 05-22<br />

3.1.6 Monitore<br />

Motivation<br />

➥ Programmierung mit Semaphoren ist schwierig<br />

➥ Reihenfolge der P/V-Operationen: Verklemmungsgefahr<br />

➥ Synchronisation über gesamtes Programm verteilt<br />

Monitor (Hoare, 1974; Brinch Hansen 1975)<br />

➥ Modul mit Daten, Prozeduren <strong>und</strong> Initialisierungscode<br />

➥ Zugriff <strong>auf</strong> die Daten nur über Monitor-Prozeduren<br />

➥ (entspricht in etwa einer Klasse)<br />

➥ Alle Prozeduren stehen unter wechselseitigem Ausschluß<br />

➥ nur jeweils ein Prozeß kann Monitor benutzen<br />

➥ Programmiersprachkonstrukt: Realisierung durch Übersetzer<br />

c○2004, Roland Wismüller 05-23<br />

3.1.6 Monitore ...<br />

Bedingungsvariable (Zustandsvariable, condition variables)<br />

➥ Zur weiteren Synchronisation zwischen Monitor-Prozeduren<br />

➥ für anwendungsspezifische Bedingungen<br />

➥ z.B. voller Puffer im Erzeuger/Verbraucher-Problem<br />

➥ Bedingungsvariable verwaltet Warteschlange blockierter<br />

Prozesse<br />

➥ Zwei Operationen:<br />

➥ wait(): Blockieren des <strong>auf</strong>rufenden Prozesses<br />

➥ signal(): Aufwecken blockierter Prozesse<br />

➥ Bedingungsvariable hat ” kein Gedächtnis“:<br />

➥ signal() weckt nur einen Prozeß, der wait() bereits<br />

<strong>auf</strong>gerufen hat<br />

c○2004, Roland Wismüller 05-24


3.1.6 Monitore ...<br />

Funktion von wait():<br />

➥ Aufrufender Prozeß wird blockiert<br />

➥ nach Ende der Blockierung kehrt wait() zurück<br />

➥ Aufrufender Prozeß wird in Warteschlange der Bedingungsvariable<br />

eingetragen<br />

➥ Monitor steht bis zum Ende der Blockierung anderen<br />

Prozessen zur Verfügung<br />

Funktion von signal():<br />

➥ Falls Warteschlange der Bedingungsvariable nicht leer:<br />

➥ mindestens einen Prozeß wecken:<br />

aus Warteschlange entfernen <strong>und</strong> Blockierung <strong>auf</strong>heben<br />

c○2004, Roland Wismüller 05-25<br />

3.1.6 Monitore ...<br />

Varianten für signal():<br />

1. Ein Prozeß wird geweckt (meist der am längsten wartende)<br />

(a) signalisierender Prozeß bleibt im Besitz des Monitors<br />

(b) geweckter Prozeß erhält den Monitor sofort<br />

i. signalisierender Prozeß muß sich erneut bewerben<br />

(Hoare)<br />

ii. signal() muß letzte Anweisung in Monitorprozedur<br />

sein (Brinch Hansen)<br />

2. Alle Prozesse werden geweckt<br />

➥ signalisierender Prozeß bleibt im Besitz des Monitors<br />

➥ Bei 1a) <strong>und</strong> 2) ist nach Rückkehr aus wait() nicht sicher,<br />

daß die Bedingung (noch) erfüllt ist!<br />

c○2004, Roland Wismüller 05-26<br />

3.1.6 Monitore ...<br />

Typische Verwendung von wait() <strong>und</strong> signal()<br />

➥ Testen einer Bedingung<br />

➥ bei Varianten 1b):<br />

➥ if (!Bedingung) wait(condVar);<br />

➥ bei Varianten 1a) <strong>und</strong> 2):<br />

➥ while (!Bedingung) wait(condVar);<br />

➥ Signalisieren der Bedingung<br />

➥ if (Bedingung hergestellt) signal(condVar);<br />

c○2004, Roland Wismüller 05-27<br />

3.1.6 Monitore ...<br />

Aufbau eines Monitors nach Hoare<br />

eintretende Prozesse<br />

Wartebereich<br />

Bedingung c1<br />

wait(c1)<br />

Bedingung cn<br />

wait(cn)<br />

signal(...)<br />

Monitor<br />

Lokale Daten<br />

Bedingungsvariablen<br />

Prozedur 1<br />

...<br />

Prozedur k<br />

Initialisierungscode<br />

Ausgang<br />

Eingang<br />

c○2004, Roland Wismüller 05-28


3.1.6 Monitore ...<br />

Semaphor-Realisierung m. Monitor (Pascal-artig, Brinch Hansen)<br />

monitor Semaphor<br />

condition nonbusy;<br />

integer count;<br />

procedure P<br />

begin<br />

count := count - 1;<br />

if count < 0 then<br />

wait(nonbusy);<br />

end;<br />

3.1.6 Monitore ...<br />

Erzeuger/Verbraucher m. Monitor (Pascal-artig, Brinch Hansen)<br />

monitor ErzeugerVerbraucher<br />

condition full, empty;<br />

integer count;<br />

procedure Insert(item: integer)<br />

begin<br />

if count = N then<br />

wait(full);<br />

insert item(item);<br />

count := count + 1;<br />

if count = 1 then<br />

signal(empty);<br />

end;<br />

procedure V<br />

begin<br />

count := count + 1;<br />

if count N do<br />

wait(full);<br />

...<br />

➥ Nachteil: viele Threads konkurrieren um Wiedereintritt in den<br />

Monitor<br />

c○2004, Roland Wismüller 05-31<br />

3.1.6 Monitore ...<br />

Java bietet Monitor-ähnliche Sprachkonzepte an<br />

➥ Klassenkonzept statt Modulkonzept<br />

➥ Synchronisierte Methoden (synchronized)<br />

➥ stehen (pro Objekt!) unter wechselseitigem Ausschluß<br />

➥ Basisklasse Object definiert Methoden wait(), notify() <strong>und</strong><br />

notifyAll()<br />

➥ alle Klassen erben diese Methoden<br />

➥ keine expliziten Bedingungsvariablen<br />

➥ nur eine implizite Bedingungsvariable pro Objekt<br />

c○2004, Roland Wismüller 05-32


3.1.7 Synchronisation mit PThreads<br />

Mutex-Variable für wechselseitigen Ausschluß<br />

➥ Verhalten wie binäres Semaphor<br />

➥ Zustände: gesperrt, frei<br />

➥ Deklaration <strong>und</strong> Initialisierung (Initialzustand: frei):<br />

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;<br />

➥ Operationen:<br />

➥ Sperren: pthread_mutex_lock(&mutex)<br />

➥ Freigeben: pthread_mutex_unlock(&mutex)<br />

➥ Sperrversuch: pthread_mutex_trylock(&mutex)<br />

➥ blockiert nicht, liefert ggf. Fehlercode<br />

c○2004, Roland Wismüller 05-33<br />

3.1.7 Synchronisation mit PThreads ...<br />

Bedingungsvariablen<br />

➥ Deklaration <strong>und</strong> Initialisierung:<br />

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;<br />

➥ Operationen:<br />

➥ Warten: pthread_cond_wait(&cond, &mutex)<br />

➥ Thread wird blockiert, mutex wird freigegeben<br />

➥ Nach Signalisierung: pthread_cond_wait kehrt erst<br />

zurück, wenn mutex wieder erfolgreich gesperrt ist<br />

➥ Signalisieren:<br />

➥ ein Thread: pthread_cond_signal(&cond)<br />

➥ alle Threads: pthread_cond_broadcast(&cond)<br />

➥ entspricht Varianten 1a) <strong>und</strong> 2) bei Monitor<br />

c○2004, Roland Wismüller 05-34<br />

3.1.7 Synchronisation mit PThreads ...<br />

Bedingungsvariablen ...<br />

➥ Herstellen der signalisierten Bedingung <strong>und</strong> Signalisierung<br />

muß bei gesperrtem Mutex erfolgen!<br />

➥ Sonst: Gefahr des lost wakeup<br />

pthread_mutex_lock(&mx);<br />

condition = true;<br />

pthread_cond_signal(&cv);<br />

pthread_mutex_unlock(&mx);<br />

3.1.7 Synchronisation mit PThreads ...<br />

Nachbildung eines Monitors mit PThreads:<br />

Erzeuger/Verbraucher-Problem<br />

Globale Variablen<br />

pthread_mutex_lock(&mx);<br />

...<br />

while (!condition)<br />

pthread_cond_wait(&cv,&mx);<br />

...<br />

pthread_mutex_unlock(&mx);<br />

c○2004, Roland Wismüller 05-36<br />

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;<br />

static pthread_cond_t full = PTHREAD_COND_INITIALIZER;<br />

static pthread_cond_t empty = PTHREAD_COND_INITIALIZER;<br />

static int count = 0;<br />

c○2004, Roland Wismüller 05-37


3.1.7 Synchronisation mit PThreads ...<br />

Einfügefunktion<br />

void Insert(int item)<br />

{<br />

pthread_mutex_lock(&mutex);<br />

while (count == N)<br />

pthread_cond_wait(&full, &mutex);<br />

insert_item(item);<br />

count++;<br />

if (count == 1)<br />

pthread_cond_signal(&empty);<br />

pthread_mutex_unlock(&mutex);<br />

}<br />

c○2004, Roland Wismüller 05-38<br />

3.1.7 Synchronisation mit PThreads ...<br />

Entfernfunktion<br />

int Remove()<br />

{<br />

int result;<br />

pthread_mutex_lock(&mutex);<br />

while (count == 0)<br />

pthread_cond_wait(&empty, &mutex);<br />

result = remove_item();<br />

count--;<br />

if (count == N-1)<br />

pthread_cond_signal(&full);<br />

pthread_mutex_unlock(&mutex);<br />

return result;<br />

}<br />

c○2004, Roland Wismüller 05-39<br />

3.1.7 Synchronisation mit PThreads ...<br />

Erzeuger <strong>und</strong> Verbraucher mit PThreads<br />

void *Producer(void *arg) void *Consumer(void *arg)<br />

{ {<br />

int item = 0; int item;<br />

int i; int i;<br />

for (i=0; i


3.1.8 Barrieren<br />

➥ Synchronisationsmechanismus für Gruppen von Prozessen<br />

bzw. Threads<br />

➥ Semantik:<br />

➥ Prozeß, der Barriere erreicht, wird blockiert,<br />

bis auch alle anderen Prozesse die Barriere erreicht haben<br />

Aufruf der Barrieren−Operation Operation kehrt zurück<br />

Prozeß A<br />

Prozeß B<br />

Prozeß B<br />

Prozeß blockiert<br />

Barriere<br />

Zeit<br />

➥ Erlaubt Strukturierung nebenläufiger Anwendungen in<br />

synchrone Phasen<br />

c○2004, Roland Wismüller 05-42

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!