4 auf 1 - Betriebssysteme und verteilte Systeme
4 auf 1 - Betriebssysteme und verteilte Systeme
4 auf 1 - Betriebssysteme und verteilte Systeme
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