[dmd-concurrency] CSP: Communicating sequential processes

Robert Jacques sandford at jhu.edu
Tue Jan 19 22:00:51 PST 2010


Communicating sequential processes and pi calculus are one of the other  
major schools of message passing. There's been some interest in it, so I'm  
digging out and summarizing some old notes of mine. I view implementing  
CSP as a good use case for D's message passing architecture; i.e. one  
should be able to write a CSP library and have it compose gracefully with  
other concurrent libraries. Most of the active research in this area is  
being done by the University of Kent  
(http://www.cs.kent.ac.uk/projects/ofa/kroc/).

CSP is built around the concept of a channel; essentially typed,  
half-duplex, synchronous point-to-point single item message passing. This  
is great for a fibers/co-routine based implementation, but bad for the  
cluster/network. The asynchronous channels, would naturally have the  
opposite properties. One of the other design patterns that works well with  
single item channels are generators (or really any fast producer/slow  
consumer problem).

Channel: Several CSP implementations have found it useful to add some  
addition state to a channel and/or have built some higher level primitives  
on-top of them.
-close/poison: closes / shuts down a channel. Very useful for  
producer/consumer processing loops. It may be useful to separate poison  
 from close, i.e chan.poison(exception).
-valid: true if the channel isn't closed/poisoned.
-blackhole: chan.send is a no-op, and chan.receive throws an exception
-broadcast/delta: 1 to N messaging
-N-way: N to N messaging
-Paraplex: Converts N T sends into a T[N] send
-Deparaplex: Converts a T[N] send into N T sends

Select: One of the key flow control primatives in CSP is the  
select/alternative. This really simplifies certain usages and is  
particularly useful in GUIs, i.e. Plan9  
(http://plan9.bell-labs.com/sys/doc/acme.pdf,  
http://plan9.bell-labs.com/sys/doc/81/2.pdf). A select statement waits on  
several guard statements. A guard statement takes either a lazy bool or a  
channel and a function/delegate. The guard it ready if the boolean is true  
or if there is a value waiting in the channel. If multiple guards are  
ready, the select only executes the first one, as determined by the  
scheduler (either round robin or priority)

while(!a_done && !b_done) {
     select(
       guard(chan1,(int v) { writefln("from chan1: ",v);}),
       guard(chan2 ,foo),                                  // ->  
foo(chan2.recv);
       guard(a_done && b_done, { writefln(“We're done”);}),
    );
}

Mobile: Essentially a unique type. It is called mobile based on it's  
usage: it's used for data that moves, i.e. is mobile between processes.

Barrier: A barrier synchronization primitive. I believe something similar  
for threads is already in druntime, though there isn't support for threads  
or network processes as far as I know.
-enroll: enrolls (adds) this process to the barrier
-resign: resigns (removes) this process from the barrier
-sync: blocks until all enrolled processes have called sync

Bucket: A bucket synchronization primitive. Again, a thread-only version  
is in druntime
-fall_into: causes this process to block until the bucket is flushed
-flush: unblocks all processes waiting on the bucket.
-flush(int N): unblock N processes from the bucket

parallel: Run multiple delegates/functions concurrently, with an implicit  
join at the end, e.g.
Channel!(int) c;
parallel( { writefln("Sending a hi-five…"); c = 5; },
           { writefln("Received a ", c());          } );

Sequence/serial: take a bunch of processes and run them sequentially

Skip: A process that terminates immediately or a guard that’s always ready

Stop: A process that does nothing but doesn’t terminate

More Useful links:
http://www.ibm.com/developerworks/java/library/j-csp3.html
http://www.ibm.com/developerworks/java/library/j-jtp11234/
http://www.ibm.com/developerworks/java/library/j-jtp10264/
http://www.cs.kent.ac.uk/projects/ofa/c++csp/

An aside: I ran across CREW (Concurrent read, exclusive write) locks again  
while making this. These have always seemed perfect for D as it has both  
const and shared/synchronized method modifiers. I don't think there's any  
blockers for implementing this, so should I file a bugzilla enhancement  
request, so it gets onto the big long todo list?









More information about the dmd-concurrency mailing list