volatile and MemoryBarrier()...

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..

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

 

Update 2: Even more great information from Joe

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

 

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

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