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.