13.Vorlesung Betriebssysteme (BTS) Christian Baun cray@unix-ag.uni-kl.de Hochschule Mannheim Fakultät für Informatik Institut für Betriebssysteme 31.5.2007
Wiederholung vom letzten Mal Deadlocks und Verhungern Betriebsmittel-Graphen Kommunikation Shared Memory Message Queues Pipes Sockets Sender-Empfänger-Beziehungen Kommunikations-Systeme 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 2
Heute Zeitlicher Aspekt der Kommunikation Synchrones Senden und Empfangen Asynchrones Senden und Empfangen Richtung der Kommunikation Kooperation Semaphore 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 3
Zeitlicher Aspekt der Kommunikation Zeitliche Aspekte sind bei Kommunikationsoperationen wichtig. Es wird unterschieden: synchrone (blockierende) Kommunikation asynchrone (nicht-blockierende) Kommunikation Bei synchroner Kommunikation gibt es eine zeitliche Beziehung zwischen Sender und Empfänger. Bei asynchroner Kommunikation gibt es diese zeitliche Beziehung nicht. Bei synchroner Kommunikation kann ein Prozess bei der Ausführung einer Senden- oder Empfangs-Funktion blockiert werden. Bei asynchroner Kommunikation wird ein Prozess nie wegen der Kommunikation blockiert. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 4
synchrones und asynchrones Senden (1) synchrones (blockierendes) Senden asynchrones (nicht-blockierendes) Senden Sender Empfänger Sender Empfänger senden senden Nachricht wartet Zwischenspeicher Nachricht empfangen wartet nicht empfangen 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 5
synchrones und asynchrones Senden (2) Blockierendes Senden Hier ist der Sender so lange in der Send-Funktion blockiert, bis der Empfänger empfangsbereit ist. Erst wenn der Empfänger empfangsbereit ist, findet die Übertragung der Nachricht statt. Nicht-Blockierendes Senden Hier wird die Nachricht des Senders in einem Zwischenspeicher (Puffer) abgelegt. Der Empfänger kann die Nachricht sofort oder später aus dem Zwischenspeicher abholen. Der Sender fährt nach der Ablage der Nachricht im Zwischenspeicher sofort mit seiner Ausführung fort. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 6
synchrones und asynchrones Empfangen (1) synchrones (blockierendes) Empfangen asynchrones (nicht-blockierendes) Empfangen Sender Empfänger Sender Empfänger empfangen empfangen wartet wartet nicht senden Nachricht senden Nachricht Nachricht geht verloren 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 7
synchrones und asynchrones Empfangen (2) Blockierendes Empfangen Hier ist der Empfänger so lange blockiert, bis er die Nachricht des Senders erhält. Nicht-Blockierendes Empfangen Der Empfänger erhält die Nachricht nur, wenn sie bereits vorliegt. Liegt die Nachricht nicht rechtzeitig vor, verzichtet der Empfänger auf die Nachricht und setzt seine Ausführung fort. Die Nachricht geht verloren. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 8
Richtung der Kommunikation Kommunikationsbeziehungen werden auch durch die Übertragungsrichtung unterschieden. Bei einer unidirektionalen Kommunikation sind die Rollen des Senders und des Empfängers fest verteilt, denn die Nachrichten werden nur in eine Richtung verschickt. Die unidirektionale Kommunikation wird auch als simplex bezeichnet. Bei einer bidirektionalen Kommunikation wechseln die Rollen des Senders und des Empfängers dynamisch. Hier werden Nachrichten in beide Richtungen übertragen. Die bidirektionale Kommunikation wird auch als duplex bezeichnet. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 9
Kooperation Kooperation Semaphor Mutex Monitor 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 10
Semaphore (1) Zur Sicherung (Sperrung) kritischer Abschnitte können außer den bekannten Sperren auch Semaphore eingetzt werden. Semaphore wurden 1965 durch E.W.Dijkstra eingeführt. Ursprünglich ist ein Semaphor eine einfache Zählersperre S mit den Operationen P(S) und V(S). Die Zugriffsoperationen sind atomar, also nicht unterbrechbar (unteilbar). Semaphore sind sogenannte Zählsperren. Das heißt, sie können auch mehreren Prozessen das Betreten des kritischen Abschnitts erlauben. Im Gegensatz zu Semaphoren können Sperren immer nur einem Prozess das Betreten des kritischen Abschnitts erlauben. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 11
Semaphore (2) Die Arbeitsweise von Semaphoren wird ersichtlich, wenn man sich folgendes Szenario vor Augen hält. In einem Geschäft steht neben dem Ein-/Ausgang ein Stapel mit Einkaufskörben. Jeder Kunde, der in das Geschäft will, muss sich einen Einkaufskorb vom Stapel nehmen. Jeder Kunde, der mit dem Einkauf fertig ist und an der Kasse bezahlt hat, muss seinen Einkaufskorb wieder auf den Stapel am Eingang zurückstellen. Ist der Stapel leer, also sind alle Einkaufskörbe vergeben, kann so lange kein neuer Kunde den Laden betreten, bis ein Einkaufskorb für ihn frei ist und auf dem Stapel liegt. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 12
Ein Semaphor besteht aus zwei Datenstrukturen COUNT: Eine ganzzahlige, nichtnegative Zählvariable. Die Variable gibt an, wie viele Prozesse das Semaphor aktuell ohne Blockierung passieren dürfen. Der Wert entspricht, gemäß dem einführenden Beispiel, der Anzahl der Körbe, die sich aktuell auf dem Stapel neben dem Ein-/Ausgang des Ladens befnden. Ein Warteraum für die Prozesse, die darauf warten, das Semaphor passieren zu dürfen. Die Prozesse sind im Zustand blockiert und warten darauf, vom Betriebssystem in den Zustand bereit überführt zu werden, wenn das Semaphor den Weg freigibt. Das Semaphor gibt den Weg frei, wenn wieder Körbe frei sind. Die Länge der Warteschlange entspricht der Anzahl der Kunden, die vor dem Laden warten, weil keine Körbe mehr frei sind. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 13
Drei Zugriffsoperationen sind möglich (1) Initialisierung: Zuerst wird ein Semaphor erzeugt oder, ein bestehendes Semaphor geöffnet. Bei einem neuen Semaphor wird zu Beginn die Zählvariable mit einem nichtnegativen Anfangswert initialisiert. Dieser Wert ist die Anzahl der Körbe, die bei Ladenöffnung am Ein- /Ausgang des Ladens bereitgestellt werden. // Operation INIT auf Semaphor SEM anwenden SEM.INIT(unsigned int init_wert) { } // Variale COUNT des Semaphors SEM mit einem // nichtnegativen Anfangswert initialisieren SEM.COUNT = init_wert; 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 14
Drei Zugriffsoperationen sind möglich (2) P-Operation (passieren): Diese Operation prüft zu allererst, ob der Wert der Zählvariable gleich 0 ist, also ob keine Körbe mehr frei sind. Ist der Wert 0, also sind keine Körbe mehr vor der Tür, wird der Prozess blockiert. Der Kunde muss jetzt vor dem Laden in der Schlange warten. Ist der Wert größer 0, wird er um 1 erniedrigt, also ein Korb entnommen. SEM.P() { // Prüfen, ob die Zählvariable gleich 0 ist if (SEM.COUNT == 0) < blockiere > } // Wenn die Zählvariable größer 0 ist, wird die // Zählvariable unmittelbar um 1 erniedrigt SEM.COUNT = SEM.COUNT - 1; 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 15
Drei Zugriffsoperationen sind möglich (3) V-Operation (freigeben): Diese Operation erhöht als erstes den Wert der Zählvariable um 1. Es wird ein Korb auf den Stapel zurückgelegt. Befinden sich Prozesse im Warteraum, wird ein Prozess deblockiert. Dem Beispiel nach kann sich ein Kunde jetzt einen Korb holen. Der gerade deblockierte Prozess setzt dann seine P-Operation fort und erniedrigt als erstes die Zählvariable. Der Kunde nimmt sich einen Korb. SEM.V() { // Die Zählvariable wird um 1 erhöht SEM.COUNT = SEM.COUNT + 1; } // Sind Prozesse im Warteraum, wird einer entblockiert if ( < SEM-Warteraum ist nicht leer > ) < entblockiere einen wartenden Prozess > 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 16
Aufbauschema des Semaphpors COUNT > 0 P-Operation COUNT == 0 Warteraum COUNT - 1 kein Prozess wartet V-Operation COUNT + 1 ein Prozess wartet entblockiere Prozess Quelle: Carsten Vogt, Betriebssysteme, Spektrum Verlag 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 17
Erzeuger/Verbraucher-Beispiel (1) Ein Erzeuger soll Daten an einen Verbraucher schicken. Ein endlicher Zwischenspeicher (Puffer) soll die Wartezeiten des Verbrauchers minimieren. Daten können vom Erzeuger in den Puffer gelegt werden und vom Verbraucher aus diesem wieder entfernt werden. Gegenseitiger Ausschluss ist notwendig, um Inkonsistenzen zu vermeiden. Der Erzeuger muss blockieren, wenn der Puffer voll ist. Der Verbraucher muss blockieren, wenn der Puffer leer ist, also keine Daten vorliegen. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 18
Erzeuger/Verbraucher-Beispiel (2) Zur Synchronisation der Zugriffe werden drei Semaphore verwendet: voll: zählt die belegten Plätze im Puffer leer: zählt die freien Plätze im Puffer mutex: zuständig für den gegenseitigen Ausschluss 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 19
Erzeuger/Verbraucher-Beispiel (3) #define N 8 // Plätze im Puffer typedef int semaphore; // Semaphore sind von Typ Integer semaphore voll = 0; // zählt die belegten Plätze im Puffer semaphore leer = N; // zählt die freien Plätze im Puffer semaphore mutex = 1; // steuert den Zugriff auf kritische Bereiche void erzeuger (void) { int daten; } while (TRUE) { // Endlosschleife erzeugedatenpaket(daten); // erzeuge Datenpaket P(leer); // Zähler für leere Plätze erniedrigen P(mutex); // in den kritischen Bereich eintreten einfuegendatenpaket(daten); // Datenpaket in den Puffer schreiben V(mutex); // kritischen Bereich verlassen V(voll); // Zähler für volle Plätze erhöhen } 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 20
Erzeuger/Verbraucher-Beispiel (4) void verbraucher (void) { int daten; } while (TRUE) { // Endlosschleife P(voll); // Zähler für volle Plätze erniedrigen P(mutex); // in den kritischen Bereich eintreten entfernedatenpaket(daten); // Datenpaket aus dem Puffer holen V(mutex); // kritischen Bereich verlassen V(leer); // Zähler für leere Plätze erhöhen verbrauchedatenpaket(daten); // Datenpaket nutzen } 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 21
Erzeuger/Verbraucher-Beispiel (5) Die Semaphore voll und leer werden gegenläufig zueinander eingesetzt. Das Semaphor leer zählt die Anzahl der freien Plätze im Puffer und wird vom Erzeuger in einer P-Operation erniedrigt und vom Verbraucher in einer V-Operation erhöht. Das Semaphor voll zählt die Anzahl der Datenpakete (belegten Plätze) im Puffer und wird vom Erzeuger in einer V-Operation erhöht und vom Verbraucher in einer P-Operation erniedrigt. Ist der Puffer vollständig belegt, also das Semaphor leer gleich 0, wird der Erzeuger blockiert. Sind keine Datenpakete im Puffer, also das Semaphor voll gleich 0, wird der Verbaucher blockiert. Das Semaphor mutex ist für den wechselseitigen Ausschluss zuständig. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 22
Binäre Semaphore Als binäre Semaphore bezeichnet man Semaphore, die mit dem Wert 1 initialisiert werden und sicherstellen sollen, dass zwei oder mehr Prozesse nicht gleichzeitig in ihre kritischen Bereiche eintreten können. Ein Beispiel für ein binäres Semaphor ist das Semaphor mutex aus dem Erzeuger/Verbraucher-Beispiel. Um den wechselseitigen Ausschluss zu garantieren, muss nur jeder Prozess, kurz bevor er in seine kritische Region eintritt, das binäre Semaphor mit einer P-Operation erniedrigen und, nachdem er die kritische Region verlassen hat, das binäre Semaphor mit einer V-Operation erhöhen. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 23
Semaphoren-Beispiel: Ping-Pong Fügen Sie in den beiden Endlosprozessen Ping und Pong Semaphorenoperationen P und V so ein, dass die Prozesse endlos PingPong, PingPong, PingPong ausgeben. Geben Sie bitte auch die Initialisierung der Semaphoren an. // Initialisierung der Semaphoren s_init (Sema_Ping, 1); s_init (Sema_Pong, 0); task Ping is task Pong is begin begin loop loop P(Sema_Ping); P(Sema_Pong); print( "Ping"); print("pong, "); V(Sema_Pong); V(Sema_ping); end loop; end loop; end Ping; end Pong; 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 24
Semaphoren-Beispiel: Drei Läufer (1) Drei Läufer sollen hintereinander eine bestimmte Strecke laufen. Der zweite Läufer darf erst starten, wenn der erste Läufer im Ziel angekommen ist. Der dritte Läufer darf erst starten, wenn der zweite Läufer im Ziel angekommen ist. Vorgeschlagen wird nebenstehende Lösung. // Initialisierung der Semaphoren s_init (Sema, 0); task Erster is < laufen > V(Sema); task Zweiter is P(Sema); < laufen > V(Sema); task Dritter is P(Sema); < laufen > Ist diese Lösung korrekt? 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 25
Semaphoren-Beispiel: Drei Läufer (2) Die Lösung ist nicht korrekt! Es existieren zwei Reihenfolgebeziehungen: Läufer 1 vor Läufer 2 Läufer 2 vor Läufer 3 Beide Reihenfolgebeziehungen verwenden das gleiche Semaphor. Es ist nicht ausgeschlossen, dass Läufer 3 mit seiner P-Operation vor Läufer 2 das Semaphor um den Wert 1 erniedrigt. Wie könnte eine korrekte Lösung aussehen? 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 26
Semaphoren-Beispiel: Drei Läufer (3) Lösungsmöglichkeit: Ein zweites Semaphor einführen, das ebenfalls mit dem Wert 0 initialisiert wird. Läufer 2 erhöht mit seiner V-Operation das zweite Semaphor und Läufer 3 erniedrigt dieses mit seiner P-Operation. // Initialisierung der Semaphoren s_init (Sema1, 0); s_init (Sema2, 0); task Erster is < laufen > V(Sema1); task Zweiter is P(Sema1); < laufen > V(Sema2); task Dritter is P(Sema2); < laufen > 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 27
Semaphore unter Linux/UNIX (1) Das Konzept der Semaphoren unter Linux/UNIX-Betriebssystemen weicht ein wenig vom Konzept der Semaphoren nach Dijkstra ab. Unter Linux/UNIX-Betriebssystemen kann die Zählvariable eines Semaphors mit einer P-Operation bzw. einer V-Operation um mehr als 1 erhöht bzw. erniedrigt werden. Es können mehrere Zugriffsoperationen auf verschiedenen Semaphoren atomar, also unteilbar, durchgeführt werden. Mehrere P-Operationen können z.b. zusammengefasst und nur dann durchgeführt werden, wenn keine der P-Operationen blockiert. Unter Linux/UNIX-Betriebssystemen führt das Betriebssystem im Kernel eine Semaphorentabelle, die Verweise auf Arrays mit Semaphoren enthält. Jedes Array beschreibt eine Gruppe von Semaphoren, die über den Index der Semaphorentabelle identifiziert wird. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 28
Semaphore unter Linux/UNIX (2) Gruppennummer Semaphorennummer innerhalb der Gruppe Semaphorentabelle 0 1 2 3 4 5 0 S 00 S 01 S 02 S 03 S 04 S 05 1 2 S 10 S 20 S 11 S 21 S 22 einzelnes Semaphor 3... S 30 S 31 S 32 S 33 S 34 n leer Semaphorengruppe Quelle: Carsten Vogt, Betriebssysgteme, Spektrum Verlag 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 29
Semaphore unter Linux/UNIX (3) Einzelne Semaphore werden über den Tabellenindex und die Position in der Gruppe (beginnend bei 0) angesprochen. Atomare Operationen auf mehreren Semaphoren können nur dann durchgeführt werden, wenn alle betreffenden Semaphore der gleichen Gruppe angehören. Linux/UNIX-Betriebssysteme stellen drei Systemaufrufe für die Arbeit mit Semaphoren bereit: semget(), semctl() und semop(). 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 30
Semaphore öffnen oder erzeugen semget() int semget(key_t key, int n_sems, int flag); Mit dieser Funktion kann ein neues Semaphor oder eine Gruppe von Semaphoren erzeugt oder ein bestehendes Semaphor geöffnet werden. Die Funktion liefert den Index der Semaphorengruppe aus der Semaphorentabelle zurück. Der Parameter key gibt die ID eines bestehenden, zu öffnenden Semaphors an. der Parameter n_seems gibt die Anzahl der Semaphore in einer Gruppe von Semaphoren an. Soll eine bereits existierende Semaphoregruppe geöffnet werden, wird im Parameter n_seems der Wert 0 übergeben. Im Fehlerfall gibt die Funktion -1 zurück. Informationen über bestehende Semaphore gibt das Kommando ipcs. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 31
Semaphore ändern semctl() int semctl(int semphoren_id, int sem_num, int komm, union semun arg); Mit dieser Funktion kann der Wert eines existierenden Semaphors oder einer Semaphorengruppe abgefragt und geändert werden und das Semaphor kann gelöscht werden. Mit dem Parameter semphoren_id wird der Index der Semaphorengruppe aus der Semaphorentabelle angegeben, auf die zugegriffen werden soll. Mit dem Parameter sem_num wird die Nummer (Position) eines einzelnen Semaphors in einer Semaphorengruppe angegeben. Mit dem Parameter komm wird angegeben, welche Aktion auf dem Semaphor oder einer Gruppe von Semaphoren ausgeführt werden soll. Im Fehlerfall gibt die Funktion -1 zurück. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 32
Semaphore ändern semctl() Mögliche Werte für den Parameter komm sind: IPC_STAT: Struktur des Semaphors abfragen. IPC_SET: Setzen der UID/GID und Zugriffsrechte. IPC_RMID: Löschen einer Semaphorengruppe. GETVAL: Den Wert der Semaphorvariablen abfragen. SETVAL: Den Wert der Semaphorvariablen setzen. GETNCNT: Abfragen der Prozesse, die darauf warten, dass die Semaphorvariable größer 0 wird. GETZCNT: Abfragen der Prozesse, die darauf warten, dass die Semaphorvariable gleich 0 wird. GETALL: Abfragen der Werte aller Semaphorvariablen. SETALL: Setzen aller Semaphorvariablen. IPC_INFO: Informationen eines Semaphors erfragen. Im Erfolgsfall gibt die Funktion 0 oder die abgefragten Werte zurück. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 33
Operationen auf Semaphoren durchführen semop() int semop(int semid, struct sembuf sem_array[], size_t n_op); Mit dieser Funktion können eine oder mehrere P-Operationen und V- Operationen ausgeführt werden. Werden mehrere Operationen ausgeführt, findet die Ausführung atomar statt. Allerdings nur, wenn sich alle betroffenen Semaphore innerhalb einer Gruppe von Semaphoren befinden. Mit dem Parameter semid wird der Index der Semaphorengruppe aus der Semaphorentabelle angegeben, auf die die Operationen angewandt werden sollen. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 34
Operationen auf Semaphoren durchführen semop() Der Parameter sem_array enthält ein Array mit P-Operationen und V- Operationen, Jeder Eintrag des Arrays enthält eine Operation und bezieht sich auf ein Semaphor der betreffenden Gruppe. Mit dem Parameter n_op wird die Anzahl der Elemente im Array sem_array mit den P-Operationen und V-Operationen angegeben. 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 35
IPC-Objekte löschen Die einfachste Möglichkeit, Semaphore, Shared Memory Segmente und Message Queues auf der Kommandozeile zu löschen, ist das Kommando ipcrm. ipcrm [-m shmid] [-q msqid] [-s semid] [-M shmkey] [-Q msgkey] [-S semkey] oder alternativ einfach... ipcrm shm SharedMemoryID ipcrm sem SemaphorenID ipcrm msg MessageQueueID 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 36
Nächste Vorlesung: 1.6.2007 13.VorlesungBetriebssysteme (BTS) Hochschule Mannheim Folie 37