Wednesday, April 14, 2010

Lock-free multi-threading

I was recently looking for a way to combine two Interlocked.CompareExchange() calls, do do something like this (atomically):

- If 0, then 1
- If 2, then 3

I looked some ways to combine two Interlocked.CompareExchange calls in sequences, but it seemed pretty impossible to ensure correctness. Then a mate referred me to Concurrent Programming on Windows. Very good - had read that one in the past.

I put together a nice generic technique in, to come up with this (some typos in the original code corrected):

public static class Concurrency
{
    public static int Atomic(ref int result, Func func)
    {
        int oldValue, newValue;
        do
        {
            oldValue = result;
            newValue = func(oldValue);
        } while (Interlocked.CompareExchange(ref result, newValue, oldValue) != oldValue);

        return oldValue;
    }
}
Which can then be used:
Concurrent.Atomic(ref val, x =>
{
    if (x == 0)
        return 1;
    if (x == 2)
        return 3;
    return x;
});
This provides a great way to combine multiple Interlocked.CompareExchange operations together in a consistent way, where there isn't a *massive* amount of contention over the result. The only down side I can see is the overhead of the delegate, which would need to be optimised out to work in a very performance intensive scenario.

0 comments: