10. Parallele Prozesse | |||||||||||||||||||
|
|||||||||||||||||||
10.6 Das Rendezvous
Ada stellt zur Interaktion von zwei Prozessen u. a. das Rendezvouskonzept zur Verfügung. Während eines Rendezvous können zwei Prozesse synchron Daten austauschen (Prozeßkommunikation). Man unterscheidet bei den an einem Rendezvous beteiligten Prozessen den Aufrufer eines Eingangs und den Anbieter eines Eingangs, der einen Eingang vereinbart und Eingangsaufrufe dafür akzeptiert. Beim Rendezvous sind die beiden Beteiligten synchronisiert, d. h. daß ein Eingangsaufrufer blockiert wird, bis sein Eingangsaufruf akzeptiert wird. Merksatz: "Wer zu früh kommt, muß warten". Ein Rendezvous wird durch den Aufruf eines (Prozeß-) Einganges eingeleitet. Wird der Aufruf akzeptiert, befinden sich beide Prozesse in einem Rendezvous. Das Rendezvous zwischen den beiden Prozessen kommt zustande, wenn der rufende Prozeß den Eingangsaufruf und der gerufene Prozeß (Anbieter) die Annahmeanweisung erreicht hat. Der zuerst zum Rendezvous eintreffende Prozeß wartet auf den Partner. Um ein Rendezvous akzeptieren zu können, muß ein Prozeß einen Eingang besitzen. Ein solcher Prozeßeingang ist identisch zu Unterprogrammen zu parametrieren. Beispiel:
Hier wird ein Prozeß mit zwei Eingängen definiert. Der erste Eingang nimmt einen Wert entgegen, der zweite gibt einen Wert heraus. Der Prozeß ist als Prozeßtyp ("type") definiert, um mehr als ein Objekt vom gleichen Typ erzeugen zu können. Ohne das Schlüsselwort"type" läge ein einziges, anonymes Prozeßobjekt vor. Der Eingang eines Prozesses kann in jedem Anweisungsteil aufgerufen werden, in dem das Prozeßobjekt sichtbar ist (Eingangsaufruf). Beispiel:
Der Aufruf eines Prozeßeingangs ähnelt also einem vollqualifizierten Prozeduraufruf. Es steht immer zuerst der Name des Prozesses und danach, durch einen Punkt getrennt, der des Eingangs, eventuell gefolgt vom Parameterteil. Akzeptieren eines Rendezvous Die Aufforderung (Ruf) zu einem Rendezvous für einen bestimmten Eingang muß von dem gerufenen Prozeß mittels der Annahmeanweisung ("accept") akzeptiert werden. Danach synchronisieren sich beide Prozesse und das Rendezvous beginnt. Beispiel:
Der gerufene Prozeß kann nur dann einen Ruf annehmen, wenn er sich in der entsprechenden Annahmeanweisung ("accept") befindet. Ein Prozeß, der sich in einer Annahmeanweisung befindet (sich also blockiert), erhält frühestens dann die Prozessorkapazität, wenn ein Ruf zu diesem Eingang an ihn ergeht. Würde ein Prozeß den Eingang"output" aufrufen und erwartete der gerufene Prozeß einen Ruf für den anderen Eingang, so läge eine Verklemmung ("deadlock") vor. Eine Verklemmung liegt immer dann vor, wenn zwei (oder mehr) Prozesse aufeinander warten (z. B. in einer Accept-Anweisung). Auch ein Prozeß, der einen seiner eigenen Eingänge aufruft, verklemmt sich unweigerlich, denn er kann nicht gleichzeitig einen Eingang aufrufen und auch einen Eingangsaufruf für diesen akzeptieren. Ein rufender Prozeß, der mit einem anderen in ein Rendezvous eintreten will, kann die Wartezeit zur Synchronisation begrenzen. Ein gerufener Prozeß kann auf ein oder mehrere alternative Rendezvous warten und diese mit Bedingungen versehen. Welches Rendezvous akzeptiert wird, ist abhängig von den jeweiligen Bedingungen. Ada definiert Sprachmittel, um nach einer vorgegebenen Wartezeit den Versuch auf Synchronisation, Aufrufen und Akzeptieren abzubrechen. Abruchbedingungen beim Aufrufen 1. Zeitlich befristeter Eingangsaufruf Die Auswahlanweisung ("select") erlaubt mittels einer Verzögerungsalternative eine Zeitschranke festzulegen, die angibt, wie lange er mindestens auf die Akzeptierung des Eingangsaufrufes warten will (timed_entry_call <BNF>). Beispiel:
Im Beispiel wird mindestens zwei Minuten lang darauf gewartet, daß der Prozeß"parallel_berechnung" den Aufruf des Einganges"input" akzeptiert. Sind zwei Minuten vergangen und der rufende Prozeß wird aktiv, so wird zunächst die Prozedur"uebergabe_nicht_moeglich" und danach die nächste Anweisung nach der Auswahlanweisung ausgeführt. 2. Bedingter Eingangsaufruf Will der rufende Prozeß nur dann in ein Rendezvous eintreten, wenn der gerufene Prozeß sofort dazu bereit ist, muß der rufende Prozeß die bedingte Auswahlanweisung benutzen. Beispiel:
Akzeptiert der Prozeß "parallel_berechnung" nicht sofort die Aufforderung zum Rendezvous, so wird "uebergabe_nicht_moeglich" und danach die nächste Anweisung nach der Auswahlanweisung ausgeführt. Damit der Prozeß die Aufforderung sofort akzeptieren kann, muß er sich schon in einer Annahmeanweisung aufhalten. 3. Asynchrone Steuerflußänderung Ein weiteres neues Sprachmittel ist die asynchrone Steuerflußänderung. Durch einen Eingangsaufruf oder durch Ablauf vorgegebener Zeit wird der Abbruch der Ausführung eines Blockes herbeigeführt. Dieser auszuführende Block befindet sich bei dieser Anweisung zwischen "then abort" und"end select". In den folgenden beiden Beispielen ist die abzubrechende Anweisung mit "Ziemlich_lange_Berechnung" bezeichnet. Beispiel 1:
Beispiel 2:
Abruchbedingungen beim Akzeptieren Anders als beim Aufrufen eines Eingangs, bei dem genau ein Eingang angesprochen werden muß, kann ein Prozeß mehrere alternative Eingänge überwachen und diese mit Bedingungen versehen. Welcher Eingang akzeptiert wird, ist abhängig von den jeweiligen Bedingungen. Es gibt drei Arten, ein Rendezvous zu akzeptieren: Siehe Befristetes Warten, Bedingtes Warten und Warten mit Prozeßbeendigung. Jede dieser Möglichkeiten kann mit einer booleschen Bedingung versehen werden, dem sogenannten Wächter. Eine Alternative zur Akzeptierung eines Rendezvous heißt offen, falls sie keinen Wächter besitzt oder die Auswertung dieses Wächters "wahr" (True) ergibt, andernfalls heißt sie geschlossen. Überwachen mehrerer Eingänge
1. Akzeptieren mit Wächter Jeder Wächter wird beim Eintritt in die Auswahlanweisung genau einmal ausgewertet. Liefert sie den Wert "wahr" (True), so gilt die Alternative als offen und wird während der gesamten Verweildauer in der Auswahlanweisung berücksichtigt. Liefert der Wächter "falsch" (False), so gilt die Alternative als geschlossen und wird während der gesamten Verweildauer in der Auswahlanweisung nicht mehr berücksichtigt. Da ein Wächter nur einmal beim Eintritt in die Auswahlanweisung ausgewertet wird, ist es unerheblich, ob er während der Verweildauer seinen Wert ändert. Beispiel:
Der Wächter darf eine beliebige boolesche Bedingung sein, also z. B. auch eine Funktion mit Ergebnistyp Boolean. Es müssen nicht alle Alternativen mit einem Wächter geschützt werden. 2. Befristetes Warten Die Akzeptierung eines Rendezvous kann durch eine Zeitschranke begrenzt werden. Diese Zeitschranke gibt die Mindestzeitdauer an, mit der auf einen Ruf gewartet wird. Diese Mindest-zeitdauer wird in der Verzögerungsalternative definiert. Beispiel 1:
Beispiel 2:
Ist mehr als ein alternativer Zweig mit einer Zeitschranke in der Auswahlanweisung vorhanden, so wird derjenige Zweig ausgewählt, dessen Zeitschranke als erste überschritten ist (frühestes Verfallsdatum). Sind mehrere identische Zeitschranken angegeben, so wird eine zufällig ausgewählt. Ein für die zeitliche Akzeptierung oft angeführtes Beispiel ist die "Toter-Mann"-Schaltung, die in Lokomotiven eingesetzt wird:
Wird eine bestimmte Taste nicht innerhalb von 30 Sekunden nach der letzten Betätigung betätigt, so wird (z. B. der Zug) sofort gebremst. 3. Bedingtes Warten Will ein Prozeß nur dann ein Rendezvous akzeptieren, wenn es sofort möglich ist und sonst nicht, so ist dies mit einem Else-Zweig zu erreichen. Beispiel 1:
Beispiel 2:
Immer dann, wenn kein anderer Prozeß bereit ist, sofort mit der gerade offenen Alternative (Eingang) in ein Rendezvous einzutreten, wird die (lokale) Prozedur "kein_rendezvous_erhalten" aufgerufen. Da die Auswahlanweisung sofort verlassen wird, wenn kein Rendezvous eingetreten ist, darf die Funktion"berechnung" nicht mehr außerhalb der Alternative stehen, denn es wird nicht immer ein Initalwert übergeben. Ein Rendezvous kommt genau dann zustande, wenn ein Prozeß einen Eingangsaufruf getätigt hat und wartet. In diesem Beispiel läuft der Prozeß ständig ohne Pause in einer Endlosschleife. Ein solches Verhalten wird als aktives Warten ("busy waiting") und in diesem speziellen Fall auch als "polling" bezeichnet. "Polling" steht allgemein für den Vorgang, daß eine Schnittstelle, hier ein Eingang, abgefragt wird, ob irgendetwas abzuholen ist und wenn nicht, die Abfrage abgebrochen und umgehend von neuem gestartet wird. "Polling" wie auch "busy waiting" beansprucht (viel) Prozessorzeit, meist ohne Ergebnis. Diese Zeit könnte anderen Prozessen zur Verfügung stehen, wenn dieser Prozeß nur ab und zu die Schnittstelle abfragte. 4. Warten mit Prozessbeendigung Ein Prozeß, der einen Eingangsaufruf akzeptiert, wartet mit Sicherheit dann vergeblich, wenn alle anderen Prozesse, die ihn für ein Rendezvous aufrufen könnten, den Status beendet haben. Durch das Akzeptieren mit einer Terminate-Alternative wird in einem solchen Fall auch der wartende Prozeß kooperativ beendet. Beispiel 1:
Beispiel 2:
Es wäre möglich, die alternative Auswahl "terminate" mit einem Wächter zu versehen. Eine"terminate"- Alternative kann keine weiteren Anweisungen enthalten. Die Reihenfolge ist unerheblich, die Terminate-Alternative kann auch am Anfang oder mitten unter anderen Alternativen stehen. Als letzte Alternative ist sie allerdings am auffälligsten und daher zu bevorzugen. Sie darf nicht mit einer Verzögerungsalternative ("delay") oder in Verbindung mit dem bedingten Warten verwendet werden. Beachte: Für den Anbieter eines Rendezvous gibt es eine Vielzahl an Möglichkeiten, den Eingangsaufruf zu akzeptieren. Neben der einfachen Accept-Anweisung gibt es das Selektive Akzeptieren, das vom Anbieter verwendet wird, um:
Für den Aufrufer eines Eingangs existieren ebenfalls Möglichkeiten, Einfluß auf das Rendezvous zu nehmen, um
|
|||||||||||||||||||
|