我正在阅读Joe Duffy关于使用双重检查锁定实现单例的这篇文章:
http://www.bluebytesoftware.com/blog/PermaLink,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx
他似乎提出的(变体)解决方案是这样的:
class Singleton { private static object slock = new object(); private static Singleton instance; private static int initialized; private Singleton() {} public Instance { get { if (Thread.VolatileRead(ref initialized) == 0) { lock (slock) { if (initialized == 0) { instance = new Singleton(); initialized = 1; } } } return instance; } }
}
我的问题是,是否仍然存在写入重新排序的危险?具体来说这两行:
instance = new Singleton(); initialized = 1;
如果这些写入被反转,那么其他一些线程仍然可以读取null.
解决方法
@H_502_20@ 我认为关键在于链接文章( http://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S5).具体来说,MS实现的.NET 2.0内存模型具有以下属性:Writes cannot move past other writes from the same thread.
Duffy提到在IA-64上做了很多工作来支持这个:
We accomplish this by ensuring writes have ‘release’ semantics on IA-64,via the st.rel instruction. A single st.rel x guarantees that any other loads and stores leading up to its execution (in the physical instruction stream) must have appeared to have occurred to each logical processor at least by the time x’s new value becomes visible to another logical processor. Loads can be given ‘acquire’ semantics (via the ld.acq instruction),meaning that any other loads and stores that occur after a ld.acq x cannot appear to have occurred prior to the load.
请注意,Duffy还提到这是MS特定的保证 – 它不是ECMA规范的一部分(至少在2006年的文章撰写时).所以,Mono可能不那么好.