Tasks and channels
RCE programs can run several tasks that talk over channels.
fn producer(out: chan i64, n: i64)
for i in 0..n
out <- i
out.close()
fn main()
let c = chan[i64](8)
spawn producer(c, 10)
var total = 0
loop
match <- c
some(v) -> total += v
none -> break
emit total
chan[i64](8)makes a channel that holds up to 8 values of typei64.spawn producer(c, 10)startsproduceras a new task.out <- isendsion the channel.<- creceives. When the channel is closed and empty, receiving givesnone.
$ rce run channels.rce
emit 45
exit status: 0
Why the result is always the same
Tasks in RCE are scheduled in ticks. In each tick, every task that can
move takes one communication step, in an order fixed by the tasks' ids.
The ids are computed from the program itself, not from a clock or a
counter. So the whole run is a function of the program and its inputs, and
running it again gives the same result. When no task can move, the run
ends with the outcome Deadlock instead of hanging.
The specification also defines select (wait on several channels) and
actor (a state with its own mailbox). See section 6.8 of the
specification.
Current limits
The reference interpreter runs tasks and channels as shown here. The Rust, Python and JavaScript emitters of chapter 15 do not translate them yet: in emitted code, channel operations trap.
What you learned
spawn,chan[T](n), send with<-and receive with<- c.- Scheduling is fixed by the program, so concurrent runs repeat exactly.