Concurrency Approaches Contrasted
December 10th, 2005
Here are a few roughly-equivalent class declarations using different languages and libraries. I say “roughly equivalent” because the implementation details and performance characteristics may actually be quite different in each case. However, the end result of each is that a function on a member variable is called in a non-blocking fashion, synchronized (presumably against other operations on the same class) with the use of some resource A.
// Vanilla C# with locks public class FooBar { private object A = new object(); private T _member = new T(); private delegate void FooBarDel(); public void Foo() { FooBarDel del = new FooBarDel(FooBar); del.BeginInvoke( new AsyncCallback(FooBarDone), del); } private void FooBar() { lock(A) { _member.DoSomething(); } } // You can typically get away without this, but // the documentation recommends otherwise. private void FooBarDone(IAsyncResult r) { FooBarDel d = r.AsyncState; d.EndInvoke(r); } } // Comega using a chord join pattern public class FooBar { private T _member = new T(); private async A(); public async Foo() & A() { _member.DoSomething(); A(); } public FooBar() { A(); } } // C# 2.0+ using CCR public class FooBar { private T _member = new T(); private Port<int> _p = new Port<int>(); public void Foo() { _p.Post(1); } public FooBar() { activate(!_p.with(delegate(int i) { _member.DoSomething(); })); } }
Looking at the other two examples I think it’s clear that C# as it stands today is lacking. That’s not exactly a groundbreaking statement, I realize, but I haven’t seen many examples putting all of these together in one spot.
Comega is very elegant in a situation as simple as this. CCR also seems less mistake-prone than the plain C# version, but the example I picked isn’t where CCR really shines.
(One thing I should say is that I’m not sure that the CCR example is correct or even compiles, since the library isn’t public yet. I worked this out from reading the whitepaper [pdf]. It’s only a few pages, so I recommend giving it a read.)
The goal of CCR has been to allow complex constructs such as this (also from the whitepaper) to be made easily, and dynamically if necessary:
// The finish operation or the update operation // execute with exclusive control, whereas the // GetState and QueryState operations execute // concurrently. Operations of either type are // interleaved safely (using the '^' operator). activate(exclusive(p.with(DoneHandler), !p.with(UpdateState)) ^ concurrent(!p.with(GetState), !p.with(QueryState)) );
Comega, on the other hand, provides static language features. The good news is that since CCR is just a library, it would be usable from a future C# (4.0, one would hope) that incorporated some of the ideas in Comega at the language level for the easier cases.
I had thought it was a shame that none of the Comega concurrency constructs had made it into the 3.0 C# specification. However, with CCR I think I can see why this is the case. CCR, or something like it, should offer a lot of power and flexibility well within the 3.0 timeframe without taking the risk of baking the ‘wrong’ keywords into C# itself.