Search code examples
c#.netlockinginterlocked

Replacing a lock with an interlocked operation


Is there anyway of replacing this code using the Interlocked.Exchange API?

if (IsWorking == false)
{
    lock (this)
    {
        if (IsWorking == false)
        {
            IsWorking = true;
        }
    }
}

Solution

  • Yes, but whether it would be useful is another matter.

    You could replace isWorking with an integer, and then use Interlocked.CompareExchange(ref isWorking, 1, 0).

    This is pointless though; either way the result at the end is that isWorking is 1, so we would have better concurrency by just replacing the code with IsWorking = true (or perhaps a VolatileWrite to ensure it was seen by other CPUs).

    Your code is probably a reduction of something like:

    if (isWorking == false)
        lock (this)
            if (isWorking == false)
            {
                DoSomethingWorthDoing();
                isWorking = true;
            }
    

    And it's the DoSomethingWorthDoing() part that falls down.

    There are ways of improving the concurrency of such double-checked locks, but it depends on a few things. One example is:

    if(someUsefulThing == null)
      Interlocked.CompareExchange(ref someUsefulThing, SomeUsefulFactory(), null);
    

    At the end of this someUsefulThing will be set to the result of SomeUsefulFactory(), and after being set it will not be set again. There will though be a period in which we might call SomeUsefulFactory() multiple times just to throw the result away. Sometimes that's a disaster, sometimes that's fine, and sometimes we could have just done no locking and been fine; it depends on just why we're concerned to share the same object here.

    There are further variants, but applicability depends on just why you care about concurrency. This code, for example, implements a thread-safe concurrent dictionary using such interlocked operations, which tends to be slower than just putting a lock around accessing a dictionary when contention is low, but much better when many threads access it at the same time.