swirl
Guide to OmniMark 9   OmniMark home
docs home 
IndexConceptsTasksSyntaxLibrariesLegacy LibrariesErrors
 
Prerequisite Concepts     Related Topics  

Coroutines

OmniMark can execute multiple computations concurrently by interleaving the execution of their actions. The interleaved computations are called coroutines.

Coroutines are an important ingredient of the streaming programming paradigm. Every coroutine in OmniMark either produces a stream or consumes it. There are four types of coroutines:

Another feature of coroutines in OmniMark is that they always exist in pairs. A string source producer coroutine is always paired with a string sink consumer coroutine, and vice versa. The same relationship exists between the coroutines of markup source and markup sink type; they are always paired together as well. The data stream produced by one coroutine, which it outputs into its #current-output, is fed to and consumed by the other coroutine through its #current-input.

To define a coroutine, use define function syntax with one of the four types listed above: for example, define string sink function. OmniMark will create a new coroutine pair whenever the function is called. The following example will serve to demonstrate some of the concepts behind coroutines in OmniMark:

  define string source function
     producer
  as
     using output as #main-output & #current-output
     repeat for integer count
        output "4fkd" % count || "%n"
     again
  
  
  process
     local integer total
  
     output "The numbers that add up to more than 100 are:%n"
     repeat scan producer
     match white-space* digit+ => n
        set total to total + n
        exit
           when total > 100
     again
     output "----%n"
     output "4fkd" % total || "%n"

In this example, the function producer defines a coroutine producing a string source. When the function is called, OmniMark creates a coroutine pair out of producer and the repeat scan loop that acts as the consumer. After that, the following things happen in order:

  1. Both coroutines are initialized for execution. If producer had any arguments, for example, they would be evaluated and passed to it, and any optional initializers would run as well.
  2. The consumer coroutine always executes first. In our example, that means that repeat scan begins to run.
  3. The match clause attempts to match a pattern against #current-input. Since there is nothing there yet, the consumer suspends and hands control over to producer. If the consumer terminated without trying to consume its input, the producer would not have run at all.
  4. The producer now gets to run. It enters the repeat for loop, outputs the first number (both to the consumer and to #main-output where we can see it) and suspends.
  5. The consumer's match clause consumes the first number, adds it to total, and loops.
  6. The two loops, repeat for and repeat scan, alternate in producing and consuming the numbers …
  7. … until the repeat scan loop is exited and the consumer terminates.
  8. At that point, OmniMark forcibly terminates producer: with no consumer to pair up with, its output is not needed any longer. If producer was left to run on its own, it would never terminate.
  9. After both coroutines are finished, the process rule continues to execute and outputs the final total.

The output of the program is:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
  ----
   105

The two coroutines in a pair form a coroutine scope: OmniMark guarantees that they have the same lifetime by synchronizing their initialization and termination.

The use of coroutines has three principal advantages:

For the most part, you do not need to concern yourself with the mechanics of coroutines. OmniMark handles all the details for you. However, there are some important restrictions you need to be aware of:

If you write code that depends on the interaction between two coroutines, you may need to be aware of the rules OmniMark uses when switching from one coroutine to another.

Prerequisite Concepts
 
  Related Topics
 
 

Top [ INDEX ] [ CONCEPTS ] [ TASKS ] [ SYNTAX ] [ LIBRARIES ] [ LEGACY LIBRARIES ] [ ERRORS ]

OmniMark 9.1.0 Documentation Generated: September 2, 2010 at 1:35:14 pm
If you have any comments about this section of the documentation, please use this form.

Copyright © Stilo International plc, 1988-2010.