next up previous
Next: Iteratoren Up: Koroutinen Previous: Koroutinen in Modula-2

Das Ulmer Koroutinenkonzept

Im Gegensatz zu Modula-2 sieht der Oberon-Report keine Koroutinen vor. Dies mag im Rahmen des übersichtlichen Züricher Oberon-Systems noch vertretbar sein - in einem allgemeinen Umfeld würde dies jedoch die Erweiterbarkeit behindern.[*] Aus diesem Grund wird analog zu Modula-2 ein Koroutinenkonzept von SYSTEM exportiert, das allerdings deutlich vereinfacht wurde und somit leichter anzuwenden ist. NEWPROCESS und TRANSFER wurden durch CRSPAWN, CRSWITCH und dem Modul Coroutines (siehe unten) ersetzt:

PROCEDURE CRSPAWN(VAR newcr: COROUTINE);
PROCEDURE CRSWITCH(dest: COROUTINE);

Im Gegensatz zu Modula-2 können Prozeduren, die eine Koroutine repräsentieren, sich selbst zu Koroutinen deklarieren, wie folgendes Beispiel zeigt:

PROCEDURE Coroutine(myparams: CoroutineParameters;
                    VAR newcr: SYSTEM.COROUTINE);
BEGIN
   (* Start als normale Prozedur *)
   SYSTEM.CRSPAWN(newcr); (* Ruecksprung zu Setup *)
   (* hier wird die Koroutine nach CRSWITCH(newcr) fortgesetzt *)
END Coroutine;

PROCEDURE Setup;
   VAR
      cr: SYSTEM.COROUTINE;
BEGIN
   Coroutine(crparams, cr);
   (* ... *)
END Setup;

Im Gegensatz zu NEWPROCESS in Modula-2 dürfen Koroutinen Parameter besitzen, da sie selbst nicht als Parameter übergeben werden und damit einem vorgegebenen Prozedurtyp entsprechen müssen. Darüber hinaus muß weder ein Stack übergeben noch die Größe des Stacks festgelegt werden.

CRSPAWN ist dadurch natürlich etwas aufwendiger als NEWPROCESS und führt folgende Schritte durch:

Auch CRSWITCH ist in der Anwendung gegenüber TRANSFER vereinfacht worden. Da die Koroutinenzeiger konstant bleiben, ist es nur noch notwendig, die Zielkoroutine anzugeben. Die Zeiger auf die zuletzt aktive Koroutine und die aktuelle Koroutine werden laufend unterhalten und sind über das Modul Coroutines zugänglich:

DEFINITION Coroutines;

   IMPORT SYS := SYSTEM, Types;

   TYPE
      Coroutine = SYS.COROUTINE;
   VAR
      defaultsize: Types.Size;
         (* die Voreinstellung fuer die Anfangsgroesse
            einer Koroutine
         *)
      source: Coroutine;
         (* die Koroutine, die zuletzt aktiv war *)
      current: Coroutine;
         (* die Koroutine, die zur Zeit aktiv ist *)

END Coroutines.

Die Zeiger source und current werden dabei von CRSWITCH gesetzt. Auf diese Weise ist es recht einfach, zur zuletzt aktiven Koroutine wieder zurückzuwechseln. In Modula-2 wurde hierfür der source-Parameter von TRANSFER verwendet.

Auf dieser Basis läßt sich leicht das Produzenten/Konsumenten-Problem lösen, wie folgendes Beispiel zeigt:[*]

PROCEDURE Produce(VAR newtoken: Token;
                  VAR producer, consumer: Coroutines.Coroutine);
   (* produziere jeweils ein Token, lege es in `newtoken' ab
      und wechsle dann zu `consumer'
   *)
   VAR
      token: Token;
BEGIN
   SYSTEM.CRSPAWN(producer);
   LOOP
      (* produziere `token' *)
      newtoken := token;
      SYSTEM.CRSWITCH(consumer);
   END;
END Produce;

PROCEDURE Consume(VAR newtoken: Token;
                  VAR producer, consumer: Coroutines.Coroutine);
   (* hole von `newtoken' jeweils ein neues Token,
      konsumiere es und wechsle dann zu `producer'
   *)
   VAR
      token: Token;
BEGIN
   SYSTEM.CRSPAWN(consumer);
   LOOP
      token := newtoken;
      (* konsumiere `token' *)
      SYSTEM.CRSWITCH(producer);
   END;
END Consume;

PROCEDURE Setup;
   VAR
      token: Token;
      producer, consumer: Coroutines.Coroutine;
BEGIN
   Produce(token, producer, consumer);
   Consume(token, producer, consumer);
   SYSTEM.CRSWITCH(producer);
END Setup;


next up previous
Next: Iteratoren Up: Koroutinen Previous: Koroutinen in Modula-2
Andreas Borchert
2/2/1998