Tutorial: Co-routines


 

Co-routine sequencing is sometimes considered as a "poor mans concurrency." This is hardly fair, since there is a trade off between the need for concurrency control and the flexibility in synchronization. Co-routines represent the trade-off where synchronization is simple, since "almost everything is a critical region." Using concurrency makes it harder to ensure correct sharing of data, but on the other hand it its sometimes easier to ensure progress in the program as a whole, because some thread will run as long as any thread can do anything.

In both cases, the modeling relation sometimes strongly suggests that alternating (co-routine) sequencing or concurrent sequencing is the natural approach to take. After all, the world is massively concurrent! On the other hand, it gets more complicated, or at least less customary, for the programmer to understand what is going on.

How does it look?

Both to get co-routine sequencing and concurrent sequencing, the notion of component is needed. A traditional BETA syntax for expressing this is the "|" marker, e.g.:

<Names> ":" "@" "|" <Merge>

This syntax has been preserved in gbeta, even though it has been reinterpreted. The full set of declarations was listed earlier, and they all include the "|".

In traditional BETA, the concept of component is at the same level as the concept of object, i.e. objects and components are fundamentally different things. In gbeta, the notion of component has been subordinated the notion of types, and the component properties (notably the posession of an execution stack) is associated with a basic pattern called component. The "|" marker is reinterpreted as a type constraint which ensures that component is present.

Example 8

As an example, we take a very famous algorithm which demonstrates that co-routines is sometimes the most natural expression of alternating processes, a slight variation of the version from Object-Oriented Programming in the BETA Programming Language:


(* FILE ex8.gb *)
-- betaenv:descriptor --
(# 
   cycle: (# do INNER; restart cycle #);
   getch: 
     (# s: @string 
     do stdio->s; (if s.length=0 then SUSPEND (* kill *) if)
     exit 1->s.at 
     #);
   symmetricCoroutineSystem:
     (# symmetricCoroutine: component
          (# resume:< 
               (# 
               do this(symmetricCoroutine)[]->next[];
                  SUSPEND
               #)
          do INNER
          #);
        next: ^symmetricCoroutine;
        run: cycle
          (# active: ^symmetricCoroutine (* currently running *)
          enter next[]
          do (if (next[]->active[])=NONE then 
                 leave Run
             if);
             NONE->next[];
             active; (* attach next component *)
             (* active 'SUSPEND'ed, 'Resumed', or terminated *)
          #)
     do INNER
     #);
   converter: @symmetricCoroutineSystem
     (# doubleA2B: @symmetricCoroutine
          (# ch: @char
          do cycle
             (# 
             do getch->ch;
                (if ch='a' then 
                    getch->ch;
                    (if ch='a' then 'b'->doubleB2C.resume else
                        'a'->doubleB2C.resume;
                        ch->doubleB2C.resume
                    if)
                 else
                    ch->doubleB2C.resume
                if)
             #)
          #);
        doubleB2C: @symmetricCoroutine
          (# ch: @char;
             resume::(# enter ch #)
          do cycle
             (#
             do (if ch
                 // 'b' then 
                    doubleA2B.resume;
                    (if ch='b' then 'c'->stdio else
                        'b'->stdio;
                        ch->stdio
                    if)
                 // '\n' then 
                    SUSPEND
                 else
                    ch->stdio
                if);
                doubleA2B.resume
             #)
          #)
     do doubleA2B[]->run
     #)
do 
   'Enter one character + [ENTER] at a time; empty input quits;\n'->stdio;
   'on the fly, "aa" becomes "b" and "bb" becomes "c".\n\n'->stdio;
   converter
#)

Naturally, the next topic is concurrency.

 


Signed by: eernst@cs.auc.dk. Last Modified: 3-Jul-01