Concurrency Approaches Contrasted

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.

Tags: , , ,

Leave a Reply