I recently discovered that there has been a significant discussion going on in the blogosphere about so called 'double checked locking'. Suffice to say I see no need for this and I find it very distasteful as a coding practice, one that can lead to developers adopting poor design ideas.
I post here the 'standard' singleton example, followed by what I think is a better solution:
public sealed class MyClass
{
private static object _synchBlock = new object();
private static volatile MyClass _singletonInstance;
//Makes sure only this class can create an instance.
private MyClass() { }
//Singleton property.
public static MyClass Singleton
{
get
{
if (_singletonInstance == null)
{
lock (_synchBlock)
{
// Need to check again, in case another cheeky thread
// slipped in there while we were acquiring the lock.
if (_singletonInstance == null)
{
_singletonInstance = new MyClass();
}
}
}
return (_singletonInstance);
}
}
}
public sealed class MyBetterClass
{
private static Int32 controller;
private const Int32 UNCREATED = 0;
private const Int32 CREATED = 1;
private static volatile MyBetterClass _singletonInstance;
//Makes sure only this class can create an instance.
private MyBetterClass() { }
//Singleton property.
public static MyBetterClass Singleton
{
get
{ // The comparison and conditional exchange of values, is ALWAYS uninterruptible
if (Interlocked.CompareExchange(ref controller, CREATED, UNCREATED) == UNCREATED)
_singletonInstance = new MyBetterClass();
return (_singletonInstance);
}
}
}
bear in mind that to all intents and purposes, the interlocked operation is very fast, it is pretty much an uninterruptible 'if then assign' that relies on (reliable) hardware to ensure (even in SMP systems) that the if will branhc true once and only once, ever. Please post here if you spot an oversight.
Hugh