One thing I love about my job is that I learn something new all the time.  Today I got a little bit smarter about volatile.  One of the devs on the Indigo team was asking about the double check locking pattern. Today the Design Guidelines doc says:

 

public sealed class Singleton {

   private Singleton() {}

   private static volatile Singleton value;

   private static object syncRoot = new Object();

 

   public static Singleton Value {

          get {

                 if (Singleton.value == null) {

                        lock (syncRoot) {

                               if (Singleton.value == null) {

                                      Singleton.value = new Singleton();

                               }

                        }

                 }

                 return Singleton.value;

          }

   }     

}

 

 

He wanted to know if “volatile” was really needed. Turns out the answer is “sorta”.  Vance, a devlead on the CLR JIT team explained that the issue is around the CLR memory model… Essentially the memory model allows for non-volatile reads\writes to be reordered as long as that change can not be noticed from the point of view of a single thread.  The issue is, of course, there is often more than one thread (like the finalizer thread, worker threads, threadpool threads, etc). volatile essentially prevents that optimization.    As a side note. notice some other folks have a little problem in this space.    A major mitigation here is that x86 chips don’t take advantage of this opportunity… but it will theoretically cause problems in IA64.  As I was writing this I noticed that Vance has already done a very good write up a while ago…

 

That part I knew… what we news to me is there is a better way to do volatile, and that is with an explicitly memory barrier before accessing the data member..   We have a an API for that: System.Threading.Thread.MemoryBarrier().   This is more efficient than using volatile because a volatile field requires all accesses to be barriers and this effects some performance optimizations. 

 

So, here is the “fixed” double check locking example..

 

public sealed class Singleton {

   private Singleton() {}

   private static Singleton value;

   private static object syncRoot = new Object();

 

   public static Singleton Value {

          get {

                 if (Singleton.value == null) {

                        lock (syncRoot) {

                               if (Singleton.value == null) {

 Singleton newVal = new Singleton();

// Insure all writes used to construct new value have been flushed.

 System.Threading.Thread.MemoryBarrier();

                                      Singleton.value = newVal;         // publish the new value

                               }

                        }

                 }

                 return Singleton.value;

          }

   }     

}

I have not completely internalized this yet, but my bet is it is still better to just make ” value” volatile to ensure code correctness at the cost of (possibly) minor perf costs.

 

Thoughts?

 

 

Update:  Vance some new information about how this works in 2.0.. 

http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/default.aspx 

 

Update 2: Even more great information from Joe

http://www.bluebytesoftware.com/blog/2007/06/09/ALazyInitializationPrimitiveForNET.aspx

 

Update 3: This gets even better with 3.5, again from Joe!

http://www.bluebytesoftware.com/blog/PermaLink,guid,a2787ef6-ade6-4818-846a-2b2fd8bb752b.aspx