using namespace std use deque use stdio.h deque q typedef int (*process_func)(process *p) struct process process_func f int pc inline void start(process *p) q.push_back(p) inline bool resume(process *p) int rv = (*p->f)(p) if rv p->pc = rv return rv run() while !q.empty() step() step() process *p = q.front() q.pop_front() if resume(p) q.push_back(p) # a new OO feature for nipl: # a method can automatically know the object that called it # by declaring a variable called "caller" at the start of its args; # this variable is passed automatically by the caller. # Someone of the wrong type will not be allowed to call it. # void * can be used to match any class # a new keyword "any *" instead of "void *" ??? struct rendezvous process *waiting rendezvous() : waiting(NULL) {} # here are the general rendezvous methods: # meet - if the partner is here, returns 0, # otherwise we wait for the partner to arrive, returns 1, # (caller must then yield) int meet(process *p) bool must_wait = !waiting if must_wait waiting = p return must_wait # pass - give control to the partner # (this works whether or not they are here already) void pass(process *p) if waiting start(waiting) waiting = p # part - finish the rendezvous # (this assumes they are here) void part() start(waiting) waiting = NULL # peer - get the partner's process pointer # or NULL if they are not here process *peer() return waiting # here - check if the partner is here bool here() return peer() != NULL # so - wait_to_get is pass, # - wait_to_put is meet, # - put is part template struct channel : rendezvous T data struct count_to_three process p channel *out int count_to_three_f(process *p) count_to_three *d = (count_to_three *)p switch p->pc 0 if d->out->meet(p) p->pc = 1 return 0 1 d->out->data = 1 d->out->part() if d->out->meet(p) p->pc = 2 return 0 2 d->out->data = 2 d->out->part() if d->out->meet(p) p->pc = 3 return 0 3 d->out->data = 3 d->out->part() return 0 struct printer process p channel *in int printer_f(process *p) printer *d = (printer *)p switch p->pc 0 while 1 p->pc = 1 d->in->pass(p) return 0 1 printf("%d\n", d->in->data) return 0 struct count_to_n process p channel *out int n int count_to_n_f(process *p) count_to_n *d = (count_to_n *)p switch p->pc 0 d->out->data = 0 while d->out->data < d->n if d->out->meet(p) p->pc = 1 return 0 1 ++ (d->out->data) d->out->part() return 0 # I think it's ok to set the initial value of the channel # before the first rendezvous - although normally when we're not # in a rendezvous the data "belongs" to the receiver, # before we start it belongs to the sender. # annoyingly I have to set it to 0 although it starts from 1, # because we can only increment the value at the rendezvous. # ... continued in design.doc # I'll try a different counter next, with a special case for the initial value. int main() channel ch ; ch.waiting = NULL count_to_three c3 = { { count_to_three_f, 0 }, &ch } printer pr = { { printer_f, 0 }, &ch } start(&c3.p) start(&pr.p) run() count_to_n cn = { { count_to_n_f, 0 }, &ch, 15 } start(&cn.p) run() return 0