down-Systemaufruf - Karl Kübel Schule

Werbung
Interprozesskommunikation (IPC)
Interprozesskommunikation
Prozesse arbeiten oft nicht allein, sondern müssen Informationen
austauschen, um eine gemeinsame Aufgabe zu erfüllen.
Prozess 0
3 wichtige Fragen sind zu klären:
Prozess 1
Interprozesskommunikation
Prozesse arbeiten oft nicht allein, sondern müssen Informationen
austauschen, um eine gemeinsame Aufgabe zu erfüllen.
Prozess 0
Prozess 1
3 wichtige Fragen sind zu klären:
Wie werden Daten ausgetauscht?
Interprozesskommunikation
Prozesse arbeiten oft nicht allein, sondern müssen Informationen
austauschen, um eine gemeinsame Aufgabe zu erfüllen.
Prozess 0
Prozess 1
3 wichtige Fragen sind zu klären:
Wie werden Daten ausgetauscht?
Wie wird sichergestellt, dass Prozesse nicht
gleichzeitig auf gemeinsame Informationen
zugreifen?
Interprozesskommunikation
Prozesse arbeiten oft nicht allein, sondern müssen Informationen
austauschen, um eine gemeinsame Aufgabe zu erfüllen.
Prozess 0
Prozess 1
3 wichtige Fragen sind zu klären:
Wie werden Daten ausgetauscht?
Wie wird sichergestellt, dass Prozesse nicht
gleichzeitig auf gemeinsame Informationen
zugreifen?
Wie wird die richtige Reihenfolge des
Zugriffs sicher gestellt?
Interprozesskommunikation
Prozesse arbeiten oft nicht allein, sondern müssen Informationen
austauschen, um eine gemeinsame Aufgabe zu erfüllen.
Prozess 0
Prozess 1
3 wichtige Fragen sind zu klären:
Wie werden Daten ausgetauscht?
Wie wird sichergestellt, dass Prozesse nicht
gleichzeitig auf gemeinsame Informationen
zugreifen?
Wie wird die richtige Reihenfolge des
Zugriffs sicher gestellt?
Synchronisationsprobleme
Kommunikationsformen
Gemeinsame Variablen: vor allem
in Ein-Prozessor und MultiprozessorSystemen mit gemeinsamem
physikalischen Speicher
Kommunikationsformen
Gemeinsame Variablen: vor allem
in Ein-Prozessor und MultiprozessorSystemen mit gemeinsamem
physikalischen Speicher
Nachrichtenaustausch: vor allem
bei verteilten Systemen, also
Kommunikation über Rechnergrenzen
hinweg
Nachrichtensysteme
Kommunikation über Nachrichten wird auch Message-Passing genannt.
Nachrichtensysteme
Kommunikation über Nachrichten wird auch Message-Passing genannt.
Gebraucht werden zwei Operationen:
send(destination, message)
Sendet eine Nachricht an einen Empfänger (destination).
receive(source, message)
Empfängt eine Nachricht von einer Quelle (source).
Nachrichtensysteme
Interessante Probleme beim Message Passing
Wie können Sender und Empfänger eindeutig zugewiesen werden?
Was passiert, wenn Nachrichten verloren gehen?
Woher weiß der Sender, dass seine Nachricht verloren gegangen ist?
Wie verhindert man, dass Prozesse Nachrichten beliebig „spammen“ können?
Nachrichtensysteme
Interessante Probleme beim Message Passing
Wie können Sender und Empfänger eindeutig zugewiesen werden?
Was passiert, wenn Nachrichten verloren gehen?
Woher weiß der Sender, dass seine Nachricht verloren gegangen ist?
Wie verhindert man, dass Prozesse Nachrichten beliebig „spammen“ können?
Technologie 12.2: Vernetzte Systeme
Synchronisationsprobleme
Probleme treten auf, wenn zwei Prozesse gleichzeitig auf
dieselbe Ressource zugreifen.
Beispiel:
Zwei Prozesse teilen sich die Variable count=5
Synchronisationsprobleme
Probleme treten auf, wenn zwei Prozesse gleichzeitig auf
dieselbe Ressource zugreifen.
Beispiel:
Prozess 1
Zwei Prozesse teilen sich die Variable count=5
Prozess 2
Synchronisationsprobleme
Probleme treten auf, wenn zwei Prozesse gleichzeitig auf
dieselbe Ressource zugreifen.
Beispiel:
Zwei Prozesse teilen sich die Variable count=5
Prozess 1
Prozess 2
Maschinenbefehle
P1:
P2:
P3:
register1 := count
register1 := register1+1
count := register1
C1:
C2:
C3:
register2 := count
register2 := register2-1
count := register2
Synchronisationsprobleme
Prozess 1
P1:
P2:
P3:
register1 := count
register1 := register1+1
count := register1
Prozess 2
C1:
C2:
C3:
register2 := count
register2 := register2-1
count := register2
Was liefert die Ausführung der Befehle in der Reihenfolge P1,P2,C1,C2,P3,C3 ?
Synchronisationsprobleme
Prozess 1
P1:
P2:
P3:
register1 := count
register1 := register1+1
count := register1
Prozess 2
C1:
C2:
C3:
register2 := count
register2 := register2-1
count := register2
Was liefert die Ausführung der Befehle in der Reihenfolge P1,P2,C1,C2,P3,C3 ?
P1:
P2:
P3:
register1 := count
register1 := register1+1
C1:
C2:
register2 := count
register2 := register2-1
C3:
count := register2
count := register1
Synchronisationsprobleme
Prozess 1
P1:
P2:
P3:
register1 := count
register1 := register1+1
count := register1
Prozess 2
C1:
C2:
C3:
register2 := count
register2 := register2-1
count := register2
Was liefert die Ausführung der Befehle in der Reihenfolge P1,P2,C1,C2,P3,C3 ?
P1:
P2:
P3:
register1 := count
register1 := register1+1
C1:
C2:
register2 := count
register2 := register2-1
C3:
count := register2
count := register1
Die Bearbeitungsreihenfolge liefert den falschen Wert 4.
Race Conditions
Race Condition: Eine Race Condition ist
eine Konstellation, in der das Ergebnis
einer Operation vom zeitlichen Verhalten
bestimmter Einzeloperationen abhängt.
Race Conditions
Race Condition: Eine Race Condition ist
eine Konstellation, in der das Ergebnis
einer Operation vom zeitlichen Verhalten
bestimmter Einzeloperationen abhängt.
Wir möchten Race Conditions unbedingt vermeiden.
Kritischer Abschnitt
•
Ein kritischer Abschnitt (critical section) ist der Teil eines Programms, in dem auf
die gemeinsam genutzten Daten zugegriffen wird.
Kritischer Abschnitt
•
Ein kritischer Abschnitt (critical section) ist der Teil eines Programms, in dem auf
die gemeinsam genutzten Daten zugegriffen wird.
Zwei Prozesse dürfen niemals gleichzeitig
in ihrem kritischen Abschnitt sein. Diese
Forderung nennt man wechselseitigen
Ausschluss (mutual exclusion).
Keine Race Conditions!
Wechselseitiger Ausschluss durch aktives Warten
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 1:
Unterbrechungen ausschalten
disable_interrupts();
critical_region();
enable_interrupts();
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 1:
Unterbrechungen ausschalten
disable_interrupts();
critical_region();
enable_interrupts();
Problem:
Prozess könnte
Unterbrechungen nicht mehr einschalten.
Prozess könnte in seinem
kritischen Bereich in eine
Endlosschleife geraten.
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 1:
Unterbrechungen ausschalten
disable_interrupts();
critical_region();
enable_interrupts();
•
Umsetzungsmöglichkeit 2:
Nutzung einer globalen Sperrvariablen
while(sperre==true)
{
wait_short_time();
}
sperre=true;
critical_region();
sperre=false;
Problem:
Prozess könnte
Unterbrechungen nicht mehr einschalten.
Prozess könnte in seinem
kritischen Bereich in eine
Endlosschleife geraten.
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 1:
Unterbrechungen ausschalten
disable_interrupts();
critical_region();
enable_interrupts();
•
Problem:
Prozess könnte
Unterbrechungen nicht mehr einschalten.
Prozess könnte in seinem
kritischen Bereich in eine
Endlosschleife geraten.
Umsetzungsmöglichkeit 2:
Nutzung einer globalen Sperrvariablen
while(sperre==true)
{
wait_short_time();
}
sperre=true;
critical_region();
sperre=false;
Problem:
Auch hier gibt es
Race Conditions.
Was passiert, wenn Prozess 0
an dieser Stelle von Prozess 1
unterbrochen wird?
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 3: Petersons Lösung für 2 Prozesse
int turn;
boolean interested[2];
Prozess 0
enter_region(0);
void enter_region(int process)
critical_region();
{
leave_region(0);
int other=1-process;
interested[process]=true;
turn=process;
while(turn==process && interested[other]==true)
{}
}
void leave_region(int process)
{
interested[process]=false;
}
Wechselseitiger Ausschluss durch aktives Warten
•
Umsetzungsmöglichkeit 3: Petersons Lösung für 2 Prozesse
int turn;
boolean interested[2];
Prozess 0
enter_region(0);
void enter_region(int process)
critical_region();
{
leave_region(0);
int other=1-process;
interested[process]=true;
turn=process;
while(turn==process && interested[other]==true)
{}
}
void leave_region(int process) Diese Lösung kann keine Race
Conditions erzeugen!
{
interested[process]=false;
}
Wechselseitiger Ausschluss durch Sleep und
Wakeup
•
Petersons Lösung arbeitet korrekt, aktives Warten ist aber eine Verschwendung von
Rechenzeit.
Wechselseitiger Ausschluss durch Sleep und
Wakeup
•
Petersons Lösung arbeitet korrekt, aktives Warten ist aber eine Verschwendung von
Rechenzeit.
•
Bessere Lösung: ein Prozess soll nicht warten, sondern sich selbst in einen
„Schlafzustand“ versetzen können. Es können dann solange andere Prozesse
bearbeitet werden, bis ein anderer Prozess ihn „aufweckt“.
Wechselseitiger Ausschluss durch Sleep und
Wakeup
•
Petersons Lösung arbeitet korrekt, aktives Warten ist aber eine Verschwendung von
Rechenzeit.
•
Bessere Lösung: ein Prozess soll nicht warten, sondern sich selbst in einen
„Schlafzustand“ versetzen können. Es können dann solange andere Prozesse
bearbeitet werden, bis ein anderer Prozess ihn „aufweckt“.
•
Wir benötigen dazu zwei Systemaufrufe:
sleep()
wakeup(process)
Versetzt den Prozess
in den Schlafzustand.
Weckt den angegebenen
Prozess auf.
Das Erzeuger-Verbraucher-Problem
Buffer
Verbraucher
Erzeuger
Problem 1: Was passiert wenn der Verbraucher lesen möchte, der Buffer aber leer ist?
Problem 2: Was passiert, wenn der Erzeuger schreiben möchte, der Buffer aber voll ist?
Das Erzeuger-Verbraucher-Problem
Buffer
Verbraucher
Erzeuger
Problem 1: Was passiert wenn der Verbraucher lesen möchte, der Buffer aber leer ist?
Problem 2: Was passiert, wenn der Erzeuger schreiben möchte, der Buffer aber voll ist?
Lösung durch Sleep und Wakeup.
Einfache Lösung Erzeuger-Verbraucher-Problem
int count = 0;
void producer()
{
int item;
while(true){
item = produce_item();
if(count==100)
sleep();
insert_item(item);
count++;
if(count==1)
wakeup(consumer);
}
}
void consumer()
{
int item;
while(true){
if(count==0)
sleep();
item = remove_item();
count--;
if(count==99)
wakeup(producer);
consume_item(item);
}
}
Einfache Lösung Erzeuger-Verbraucher-Problem
int count = 0;
void consumer()
void producer()
{
{
int item;
int item;
while(true){
while(true){
if(count==0)
item = produce_item();
sleep();
item = remove_item();
if(count==100) Lösung ist falsch!
count--;
sleep();
if(count==99)
Race Conditions sind möglich!
insert_item(item);
wakeup(producer);
count++;
consume_item(item);
if(count==1)
}
}
wakeup(consumer);
}
}
Einfache Lösung Erzeuger-Verbraucher-Problem
int count = 0;
void producer()
{
int item;
while(true){
item = produce_item();
if(count==100)
sleep();
insert_item(item);
count++;
if(count==1)
wakeup(consumer);
}
}
void consumer()
{
int item;
while(true){
if(count==0)
sleep();
item = remove_item();
count--;
if(count==99)
wakeup(producer);
consume_item(item);
}
}
Wird der Consumer hier unterbrochen, kurz
bevor er sleep aufruft, so läuft der wakeup des
Producers ins Leere und der Consumer schläft
ewig. Irgendwann schläft auch der Producer
ein und kann nicht mehr aufgeweckt werden.
Lösung durch Semaphoren
•
Semaphoren sind spezielle Variablen (und speichern meist ganze Zahlen).
•
Zugriff auf Semaphoren nur über die Systemaufrufe up und down möglich
•
Um Race Conditions zu vermeiden, werden Unterbrechungen vom Betriebssystem
ausgeschaltet, während up oder down abgearbeitet wird..
.
Lösung durch Semaphoren
•
Semaphoren sind spezielle Variablen (und speichern meist ganze Zahlen).
•
Zugriff auf Semaphoren nur über die Systemaufrufe up und down möglich
•
Um Race Conditions zu vermeiden, werden Unterbrechungen vom Betriebssystem
ausgeschaltet, während up oder down abgearbeitet wird.
down-Systemaufruf
down(semaphore s)
{
if(s==0)
sleep();
s--;
}
.
.
Lösung durch Semaphoren
•
Semaphoren sind spezielle Variablen (und speichern meist ganze Zahlen).
•
Zugriff auf Semaphoren nur über die Systemaufrufe up und down möglich
•
Um Race Conditions zu vermeiden, werden Unterbrechungen vom Betriebssystem
ausgeschaltet, während up oder down abgearbeitet wird.
.
down-Systemaufruf
up-Systemaufruf
down(semaphore s)
{
if(s==0)
sleep();
s--;
}
up(semaphore s)
{
s++;
if(s==1)
wakeup(randomProcess);
}
War die Semaphore vorher Null, wird zufällig
einer der schlafenden Prozesse aufgeweckt.
Lösung durch Semaphoren
semaphore mutex = 1;
semaphore empty = 100;
semaphore full = 0;
void producer()
{
int item;
while(true){
item = produce_item();
down(empty);
down(mutex);
insert_item(item);
up(mutex);
up(full);
}
}
void consumer()
{
int item;
while(true){
down(full);
down(mutex);
item = remove_item();
up(mutex);
up(empty);
consume_item(item);
}
}
Lösung durch Semaphoren
semaphore mutex = 1;
semaphore empty = 100;
semaphore full = 0;
Die Semaphoren empty und full zählen die Anzahl
der vorhandenen Nachrichten und synchronisieren
damit die Aktionen von Producer und Consumer.
void producer()
{
int item;
while(true){
item = produce_item();
down(empty);
down(mutex);
insert_item(item);
up(mutex);
up(full);
}
}
void consumer()
{
int item;
while(true){
down(full);
down(mutex);
item = remove_item();
up(mutex);
up(empty);
consume_item(item);
}
}
Lösung durch Semaphoren
semaphore mutex = 1;
semaphore empty = 100;
semaphore full = 0;
Die Semaphore mutex nimmt nur die beiden Werte
0 und 1 an. Sie steuert den Zugang zum kritischen
Bereich von Consumer und Producer. Eine solche
Semaphore wird auch Mutex genannt.
void producer()
{
int item;
while(true){
item = produce_item();
down(empty);
down(mutex);
insert_item(item);
up(mutex);
up(full);
}
}
void consumer()
{
int item;
while(true){
down(full);
down(mutex);
item = remove_item();
up(mutex);
up(empty);
consume_item(item);
}
}
Kritischer Bereich
Typische Synchronisationsprobleme
Typische Synchronisationsprobleme:
–
–
–
–
–
Erzeuger-Verbraucher-Problem
Raucherproblem
Speisende-Philosophen-Problem
Leser-Schreiber-Problem
Schlafender-Friseur-Problem
Typische Synchronisationsprobleme
Typische Synchronisationsprobleme:
–
–
–
–
–
Erzeuger-Verbraucher-Problem
Raucherproblem
Speisende-Philosophen-Problem
Leser-Schreiber-Problem
Schlafender-Friseur-Problem
Alle diese Probleme können mit Hilfe von
Semaphoren und Mutexen gelöst werden.
Typische Synchronisationsprobleme
Typische Synchronisationsprobleme:
schon behandelt – Erzeuger-Verbraucher-Problem
–
–
–
–
Raucherproblem
Speisende-Philosophen-Problem
Leser-Schreiber-Problem
Schlafender-Friseur-Problem
Alle diese Probleme können mit Hilfe von
Semaphoren und Mutexen gelöst werden.
Typische Synchronisationsprobleme
Typische Synchronisationsprobleme:
schon behandelt – Erzeuger-Verbraucher-Problem
–
behandeln sie als TNW –
–
behandeln wir jetzt –
Raucherproblem
Speisende-Philosophen-Problem
Leser-Schreiber-Problem
Schlafender-Friseur-Problem
Alle diese Probleme können mit Hilfe von
Semaphoren und Mutexen gelöst werden.
Problem des schlafenden Friseurs
-
1 Friseur
-
1 Friseur-Stuhl
-
n Stühle für wartende Kunden
-
Gibt es keine wartenden Kunden,
schläft der Friseur.
-
Kommt ein Kunde herein, muss er
den schlafenden Friseur wecken.
-
Kommt ein Kunde herein, während
ein anderer Kunde frisiert wird,
setzt er sich hin (falls Plätze frei sind)
oder verlässt den Laden.
Problem des schlafenden Friseurs
const int CHAIRS = 5;
semaphore customers = 0;
semaphore barbers=0;
semaphore mutex=1;
int waiting = 0;
void barber()
{
while(true){
down(customers);
down(mutex);
waiting--;
up(barbers);
up(mutex);
cut_hair();
}
}
void customer()
{
down(mutex);
if(waiting<CHAIRS){
waiting++;
up(customers);
up(mutex);
down(barbers);
get_haircut();
} else {
up(mutex);
}
}
Kritische Abschnitte und Semaphoren in
Java
Kritische Abschnitte in Java durch den Modifier synchronized markieren:
synchronized void foo()
{
i++;
}
Kritische Abschnitte und Semaphoren in
Java
Kritische Abschnitte in Java durch den Modifier synchronized markieren:
synchronized void foo()
{
i++;
}
Semaphoren durch die Klasse Semaphore:
Herunterladen