PDC05: Double-check locking fixed in 2.0

After a nice introductory session by Jan Gray, Joe Duffy delivered a much more in depth talk on multithreading issues in .NET. Joe is a PM on the CLR team with responsibility for the System.Threading namespace, so if anyone knows the details on this, he does. He made one interesting point about the double-check locking pattern, which kind of did and kind of didn’t work in 1.1. Double-check locking is an attempt to avoid the overhead of creating a lock by checking a value before entering the lock. The value is then retested inside the lock.

if (instance == null)
{
   lock (creationLock)
   {
      if (instance == null)
         instance  = new Singleton();
   }
}
return instance;

The idea is that, once the instane is created, you never need to use the lock. In theory this is a pretty clever trick, but there’s a problem: modern processors can reorder instructions for performance reasons, which means that some of the assumptions made by the double-check pattern will not always be true. In the singleton example, if there are instructions to execute inside the constructor, instance may be set to a non-null value before the constructor completes, and therefore before the lock is exited. The result of this is that an invalid reference to instance is returned to the caller. For more details on this, read this great post by Chris Brumme.

Processors make various optimizations like these, but for the most part programmers are shielded from this complexity by a memory model defined by the language or runtime which states which optimizations can occur, regardless of what the processor wants to do.

The 1.1 version of the Common Language Infrastructure spec had a relatively weak memory model which did not prevent this specific optimization from taking place, so the double-check pattern was not guaranteed to work. In reality however, the x86 processors (the only ones supported by the offical .NET 1.1 release) don’t reorder instructions in this way, so the double-check pattern did in fact work on that platform.

The good news is that the new 2.0 version of the CLI spec includes a stricter memory model which clears up all this confusion and ensures the double-check pattern will work.

Comments are closed.