15. Cooperative coroutines

image_pdfimage_print

In this chapter, we introduce coroutines, which represent activities that may be suspended and later resumed at the point of suspension. Suspension may take place at several points during the activity.

In its simplest form a coroutine is like a method object where execution may be temporarily suspended and later resumed. 

In its most general form, it is like a parallel object in the sense that a coroutine object may execute methods and thus constitute an invocation stack (stack) as described in section . The method object currently being executed may suspend the whole coroutine object including the stack. The difference is that two or more parallel objects may execute in parallel whereas at most one coroutine object at a time may be executed. This has the advantage that two or more coroutine objects cannot simultaneously access the same data as is the case for parallel objects.

The scheduling of coroutine objects is called cooperative scheduling since the programmer has to be explicit about when/where a coroutine object suspends its execution and about which coroutine object to execute/resume next. 

In a later chapter, we introduce preemptive coroutines, where execution may be preempted. These coroutine objects are even closer to process objects. The coroutines described in this chapter is often called cooperative coroutines.

Cooperative coroutines can be used for a number of useful algorithms, which we will give examples of later in this chapter.

A coroutine object may suspend execution by executing a suspend statement:

aCoroutineObj.suspend

where aCoroutineObj must be an expression that evaluates to a reference to the coroutine object that executes the statement.

Execution may later be resumed by execution of a resume statement:

resume(aCoroutineObj)

where aCoroutineObj must be an expression that evaluates to a reference to a coroutine object.

A sketch of using suspend and resume is shown in the following example:

      coroutineSketch: obj
         class CoroutineEx: 
            ...
L2:         this(CoroutineEx).suspend
L5:         stmt 
            ...
         aCoroutineObj: ref CoroutineEx
L1:      aCoroutineObj := CoroutineEx
L3:      ...  
L4:      resume(aCoroutineObj)
         ...

We have inserted labels L1L5 before some of statements in the above code to be able to refer to these in the text below.

The object coroutineSketch has the attributes:

  • Class CoroutineEx describes objects that include a suspend statement.
  • A variable reference aCoroutineObj of type CoroutineEx.
  • An instance of CoroutineEx is generated and assigned to aCoroutineEx at the label L1.
  • As part of the generation of this object, its items are executed.
  • When execution of the CoroutineEx object arrives at L2, its execution is suspended.
  • Control then returns to coroutineSketch, which is the invoker of CoroutineEx, and execution continues at L3.
  • At L4, execution of aCoroutineObj is resumed by execution of the resume statement resume(aCoroutineObj).
  • This implies that execution of aCoroutineObj is resumed at stmt L5

When a coroutine has no more statements to execute, it terminates execution in the same way as a method object or material object.

In the next section, we will show concrete examples of using coroutines.