next up previous
Next: Das Ulmer Koroutinenkonzept Up: Koroutinen Previous: Einführung

Koroutinen in Modula-2

Modula-2 offeriert Koroutinen auf Basis von zwei Operationen aus dem Modul SYSTEM:

PROCEDURE NEWPROCESS(proc: PROC;
                     addr: ADDRESS; size: CARDINAL;
                     VAR new: ADDRESS);
PROCEDURE TRANSFER(VAR source, destination: ADDRESS);

NEWPROCESS kreiert eine neue Koroutine mit einem Stack, dessen Anfangsadresse und Größe mit addr und size gegeben wird. Die Koroutine beginnt dann später die Ausführung mit dem Aufruf der parameterlosen Prozedur proc. Ein Verweis auf die neue Koroutine wird mit new zurückgeliefert.

Einer der Nachteile von NEWPROCESS ist der Zwang, globale Variablen zur Parametrisierung der Koroutine verwenden zu müssen. Dies führt zu folgendem typischen Aufsetzen einer Koroutine:

VAR (* globale Variablen *)
   crparams: CoroutineParameters;
      (* die Parameter der Koroutine *)
   source: ADDRESS;
      (* die Koroutine, die zuletzt aktiv war *)
   newcr: ADDRESS;
      (* die Koroutine, die von NEWPROCESS zurueckgeliefert wird *)

PROCEDURE Coroutine;
   VAR
      myparams: CoroutineParameters;
BEGIN
   (* kopiere die Parameter und kehre sofort wieder zurueck *)
   myparams := crparams;
   TRANSFER(newcr, source);

   (* Rest der Koroutine *)
END Coroutine;

PROCEDURE SetupCoroutine(params: CoroutineParameters;
                         proc: PROC;
                         stackaddr: ADDRESS;
                         stacksize: CARDINAL);
   (* kreiere eine Koroutine und uebergib die Parameter *)
BEGIN
   NEWPROCESS(proc, stackaddr, stacksize, newcr);
   crparams := params;
   TRANSFER(source, newcr);
END SetupCoroutine;

Hierbei wird jede neue Koroutine sofort nach dem Kreieren gestartet, damit sie die Parameter zu sich kopieren kann. Nachdem dies geschehen ist, kehrt sie sofort wieder zurück, da üblicherweise der Rest der Koroutine die Existenz weiterer Koroutinen voraussetzt.

NEWPROCESS und TRANSFER werden von nahezu jeder Modula-2-Implementierung unterstützt und erscheinen damit auf den ersten Blick sehr portabel. Allerdings ist die anzugebene Stackgröße sehr systemabhängig. Da der Stack mit Anfangsadresse und Größenangabe fest vom Aufrufer vorgegeben werden muß, ist es konzeptionell unmöglich, Koroutinen mit wachsendem Stack zu unterstützen.

TRANSFER hat zwei VAR-Parameter: source und destination. Dies ermöglicht zwei Techniken zur Allokation der Verwaltungsinformation für Koroutinen:

Die erste Koroutine spielt eine Sonderrolle, da sie implizit während des Programmstarts kreiert wird. Der Zeiger auf die zugehörige Verwaltungsinformation wird durch den ersten Aufruf von TRANSFER bekannt. Damit ist klar, daß zumindest hierfür source als VAR-Parameter von TRANSFER benötigt wird. Dazu ist entweder die zweite Technik oder ein vorher nicht sichtbarer Zeiger auf die Verwaltungsinformation notwendig. Entsprechend könnte man auf den source-Parameter verzichten, wenn man die erste Technik verwendet und den Zeiger auf die erste Koroutine bzw. die zuletzt aktive Koroutine von Anfang an zugänglich macht.

Die zweite Technik führt zudem zu veralteten Koroutinenzeigern, wie folgendes Beispiel zeigt:

VAR
   main, newcr: ADDRESS;

PROCEDURE Coroutine;
   VAR
      cr: ADDRESS;
BEGIN
   TRANSFER(cr, main);
   (* ... *)
END Coroutine;

PROCEDURE Setup;
BEGIN
   NEWPROCESS(Coroutine, addr, size, newcr);
   TRANSFER(main, newcr);
   (* newcr ist inzwischen ein veralteter Zeiger *)
END Setup;


next up previous
Next: Das Ulmer Koroutinenkonzept Up: Koroutinen Previous: Einführung
Andreas Borchert
2/2/1998