I have read a lot about the dangers of double checked locking and I would try hard to stay away of it, but with that said I think they make a very interesting read.
I was reading this article of Joe Duffy about implementing singleton with double checked locking: http://www.bluebytesoftware.com/blog/PermaLink,guid,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx
And the (variant of) solution he seemed to propose is this:
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;
}
}
}
My question is, doesn't that still have the danger of writes being reordered? Specifically these two lines:
instance = new Singleton();
initialized = 1;
If those writes are inverted, then some other thread can still read null.
Double-checked locking is a pattern meant for reducing the overhead of locking. First, the locking condition is checked without synchronization. And only if the condition is met, the thread will try to get a lock. Thus, the locking would be executed only if it was really necessary.
Double-checked locking is a common pattern for lazy initialization of a field accessed by multiple threads.
In software engineering, double-checked locking (also known as "double-checked locking optimization") is a software design pattern used to reduce the overhead of acquiring a lock by testing the locking criterion (the "lock hint") before acquiring the lock.
Ans. There is no mapping of single ton with number of processor of the system. So double check locking will not fail depending on number of processor.
I think the key is in the linked article (http://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S5). Specifically that the MS-implemented .NET 2.0 memory model has the following property:
Writes cannot move past other writes from the same thread.
Duffy mentions that a lot of work was done to support this on the 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.
Note that Duffy also mentions that this is an MS-specific guarantee - it's not part of the ECMA spec (at least as of the the article's writing in 2006). So, Mono might not be as nice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With