Universität Ulm - Abteilung Angewandte Informationsverarbeitung
6. Übungsblatt zur Vorlesung Systemnahe Software II
Abgabetermin: Montag, 14.06.2004
Poll und Pipes (10 Punkte)
Häufig steht man (vorallem auch im Zusammenhang mit Netzwerkanwendungen)
vor dem Problem, daß man nicht nur von einem Filedeskriptor Daten
entgegen nehmen möchte, sondern von mehreren. Allerdings kann ein
normales Lesen von einem der Filedeskriptoren dazu führen, daß der
Prozeß blockiert wird, wenn dort gerade keine Daten zur Verfügung stehen.
Solange der Prozeß blockiert ist, können dann auch Daten, die auf
anderen Filedeskriptoren zur Verfügung stehen nicht bearbeitet werden.
Es wäre also praktisch, wenn man vor dem eigentlichen Lesen feststellen
könnte, ob von einem Filedeskriptor gelesen werden kann, ohne daß der
Prozeß dadurch blockiert wird. Analog gilt das natürlich auch beim Schreiben.
Der Systemaufruf poll (siehe auch ``man poll'') ist hierbei hilfreich.
Diesem Systemaufruf wird eine Liste von Filedeskriptoren übergeben. Für
jeden Filedeskriptor wird zusätzlich angeben, was wir mit diesem Filedeskriptor
machen wollen (lesen, schreiben oder beides). Der Systemaufruf poll
blockiert dann den Prozeß so lange, bis mindestens eine der Aktionen
ohne Blockieren durchgeführt werden kann. Zusätzlich kann noch ein
Zeitlimit angegeben werden, dann wartet poll höchstens so lange.
(Wie bei blockierenden Systemaufrufen üblich wird poll zusätzlich auch
von einem eintreffenden Signal unterbrochen.) Der Rückgabewert gibt an,
wieviele Filedeskriptoren die gewünschte Operation jetzt erlauben.
Um welche Filedeskriptoren es sich dabei genau handelt kann dann der
übergebenen Liste entnommen werden (siehe nächster Abschnitt).
Jeder Filedeskriptor in der oben erwähnten Liste wird durch eine Struktur
vom Typ struct pollfd beschrieben. Diese Datenstruktur enthält
drei Felder:
- fd
- Die Nummer des Filedeskriptors. Wenn dieser Wert kleiner als
0 ist, wird dieser Listeneintrag von poll ignoriert.
- events
- Hier wird durch verschiedene Flags angegeben, welche
Aktion wir gerne mit dem Filedeskriptor durchführen würden.
Interessant für uns sind die Flags:
- POLLIN
- Wir würden gerne lesen
- POLLOUT
- Wir würden gerne schreiben
- revents
- Dieses Feld wird von poll verwendet, um uns nach
der Rückkehr des Systemaufrufs mitzuteilen, welche der verlangten
Aktionen jetzt mit diesem Filedeskriptor ohne Blockieren durchgeführt
werden können. Wenn POLLIN gesetzt ist, dann kann mindestens ein
Zeichen gelesen werden, wenn POLLOUT gesetzt ist, dann kann mindestens
ein Zeichen geschrieben werden. Zusätzlich kann noch das Flag POLLHUP
gesetzt sein, wenn das andere Ende der Dateiverbindung (z.B. bei einer
Pipe) geschlossen wurde.
Zunächst soll eine Prozedur geschrieben werden, die einen Kindprozeß
erzeugt, der über eine pipe mit dem Vater verbunden ist. Dieser Kindprozeß
soll in einer Schleife eine zufällige Zeit zwischen 2 und 10 Sekunden
schlafen, dann einen ebenfalls zufälligen Buchstaben in die Pipe zum
Vater schreiben. Die Schleife soll zwischen 3 und 5 mal durchlaufen werden
(ebenfalls zufällig ausgewählt). Jedes Mal, wenn der Kindprozeß ein
Zeichen in die Pipe schreibt, soll er dieses Zeichen auch zusammen mit seiner
Prozeß-ID auf die Standardausgabe ausgeben.
Hinweis: Die Funktion rand erzeugt Zufallszahlen. Es empfiehlt
sich in jedem neu erzeugten Prozeß vor dem ersten Aufruf von rand
einmal srand(time(0) + getpid()); aufzurufen.
Der Vaterprozeß soll gleichzeitig 5 Kindprozesse wie oben beschrieben
starten, von denen jeder über eine eigene Pipe mit dem Vater kommuniziert.
Sobald von einer dieser Pipes ein Zeichen gelesen werden kann, soll der
Vater dieses Zeichen lesen und zusammen mit der Prozeß-ID des Kindprozeßes,
von dem er es gelesen hat ebenfalls auf die Standardausgabe ausgeben. Ziel
ist es, daß die Ausgabe des Vaters und die zugehörige Ausgabe des
Kindprozesses zeitgleich erfolgen! Dazu soll poll wie oben beschrieben
verwendet werden.
Viel Erfolg!
Christian Ehrhardt