By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,449 Members | 1,601 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,449 IT Pros & Developers. It's quick & easy.

Simple and fast Singleton pattern for ya.

P: n/a
FYI.
/// <summary>
/// Author: William Stacey
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>
public class SingletonClass
{
// Vars used by singleton logic.
private static int created = 0; // No object created yet.
private static SingletonClass singletonInstance = null;
// End singleton vars.

// Other private/public vars as needed in class.
private string name;

public SingletonClass()
{
name = "MyName";
Console.WriteLine("Created MyName.");
//other stuff...
}

/// <summary>
/// Returns single instance of SingletonClass if it exists. Otherwise
/// create it, store the reference and return the singleton.
/// This uses very fast Interlocked method that does its work via CPU
/// instructions in an atomic way. Almost as fast as an "if" test, while
/// being thread safe and not requiring kernel mode switch or other
locking.
/// </summary>
/// <returns>The singleton object.</returns>
public static SingletonClass GetInstance()
{
if ( Interlocked.Exchange(ref created, 1) == 1 )
return singletonInstance;
singletonInstance = new SingletonClass();
return singletonInstance;
}

/// <summary>
/// Reset "created" to zero. Next call to GetInstance() will create
/// a new SingletonClass obj. Can be used as to "refresh" and create
/// a new object daily or per some other event. This method is thread
safe.
/// </summary>
public static void ResetSingleton()
{
Interlocked.Exchange(ref created, 0);
}

public string Name
{
get { return this.name; }
}
}

--
William Stacey, MVP

Nov 15 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
William Stacey <st***********@mvps.org> wrote:
FYI.
/// <summary>
/// Author: William Stacey
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>


That's not threadsafe. There are two main problems:

1) Threads could end up with a return value of null if they call
GetInstance just after another call to GetInstance which has set the
"created" flag but not actually created the instance yet.

2) Threads could end up with a reference to the singleton before it has
finished being constructed - the reference assignment could be
rearranged to before the content of the actual constructor. You don't
have any memory barriers, so there's no guaranteed ordering of the
reads and writes.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #2

P: n/a
Thanks for seeing that Jon. There was a small window there. Here is the
fix to correct for that possibility.
We use a lock once, in the case where multiple threads actually try to get
the first instance at the "same" time.
The first thread to get the lock, will create the instance. If multiple
threads happen to wait on the lock at same time before the instance is
created, they will "wake" up to see instance was created and return it. Any
future threads will not hit the lock, but just do the quick
interlocked.compareexchange to test for created. So except for the noted
exception on first use, no expensive locks are hit. Cheers!

/// <summary>
/// Fast and simple way to implement a singleton pattern without resorting
/// to nested classes or other static vodo. Can also be easily converted to
/// allow "n" number of instances to be created.
/// </summary>
public class SingletonClass
{
// Vars used by singleton logic.
private static int created = 0; // No object created yet.
private static SingletonClass singletonInstance = null;
//Our private lock object. We could have used typeof(SingletonClass)
instead.
private static object syncLock = new object();
// End singleton vars.

// Other private/public vars as needed in class.
private string name;

public SingletonClass()
{
name = "MyName";
Console.WriteLine("Created MyName.");
}

/// <summary>
/// Returns single instance of SingletonClass if it exists. Otherwise
/// create it, store the reference and return the singleton.
/// This uses very fast Interlocked method that does its work via CPU
/// instructions in an atomic way. Almost as fast as an "if" test, while
/// being thread safe and not requiring kernel mode switch or other
locking.
/// </summary>
/// <returns>The singleton object.</returns>
public static SingletonClass GetInstance()
{
// If instance already created, "created" var will be 1, so return
instance.
if ( Interlocked.CompareExchange(ref created, 1, 1) == 1 )
return singletonInstance;

// Singleton not created yet, get the lock to create
// the instance atomically. We only incur lock penalty on first
// use/creation. After that, we don't hit this lock and rely only
// on the test above to see if instance created.
lock(syncLock)
{
// If two, or more, threads happen to be wait on lock at same time
// (i.e. threads herding at startup. ) check again as the first thread to
get the lock
// would have already created the singleton. In the unlikely event that
the thread happened
// to die or be aborted between the three lines before it sets "created"
to 1, this still works
// as long as "lock" gives the lock to another waiting thread - which is
does.
if ( created == 1 )
return singletonInstance;

//Singleton not create yet, so create it and set the created flag
//using InterlockedExchange. Flag not set until Singleton created and
reference var set.
singletonInstance = new SingletonClass();
Interlocked.Exchange(ref created, 1);
}
return singletonInstance;
}

public string Name
{
get { return this.name; }
}
}
Nov 15 '05 #3

P: n/a
William Stacey <st***********@mvps.org> wrote:
Thanks for seeing that Jon. There was a small window there. Here is the
fix to correct for that possibility.
We use a lock once, in the case where multiple threads actually try to get
the first instance at the "same" time.
The first thread to get the lock, will create the instance. If multiple
threads happen to wait on the lock at same time before the instance is
created, they will "wake" up to see instance was created and return it. Any
future threads will not hit the lock, but just do the quick
interlocked.compareexchange to test for created. So except for the noted
exception on first use, no expensive locks are hit. Cheers!


Nope, you've then got the same problem as the normal double-check lock
algorithm - you could see the reference to the singleton before it's
properly initialised.

You basically need a memory barrier there *somewhere*.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #4

P: n/a
Not exactly what happens here. This is not the same as the double checked
issue. DCL uses an unsynchronized testing of the object reference. So the
ref could be assigned by thread1 and then context switch, then thread2 could
get that ref and try to use it before construction. This does not happen
here because construction is completed before the interlock releases the
lock. The actual creation is protected by a memory barrier using the
"lock()". The assignment also creates a "write" barrier on the ref from
doco I have seen. Only then is the flag set atomically. If we want to be
really sure, we could also add a Thread.MemoryBarrier() instruction before
we open the lock like so:
....
Thread.MemoryBarrier();
Interlocked.Exchange(ref created, 1);
....

--
William Stacey, MVP

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
William Stacey <st***********@mvps.org> wrote:
Thanks for seeing that Jon. There was a small window there. Here is the fix to correct for that possibility.
We use a lock once, in the case where multiple threads actually try to get the first instance at the "same" time.
The first thread to get the lock, will create the instance. If multiple
threads happen to wait on the lock at same time before the instance is
created, they will "wake" up to see instance was created and return it. Any future threads will not hit the lock, but just do the quick
interlocked.compareexchange to test for created. So except for the noted exception on first use, no expensive locks are hit. Cheers!


Nope, you've then got the same problem as the normal double-check lock
algorithm - you could see the reference to the singleton before it's
properly initialised.

You basically need a memory barrier there *somewhere*.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 15 '05 #5

P: n/a
William Stacey <st***********@mvps.org> wrote:
Not exactly what happens here. This is not the same as the double checked
issue. DCL uses an unsynchronized testing of the object reference.
But that's not the problem with DCL - it then uses a synchronized
testing of the object reference if it was null.

The problem with the DCL is that write-ordering isn't guaranteed unless
you've got a memory barrier, so the reference itself can be written
before object has finished initializing. I don't see anything in your
code to stop a second thread correctly seeing that a first thread is
initializing the object, and then waiting until that initialization is
finished.
So the
ref could be assigned by thread1 and then context switch, then thread2 could
get that ref and try to use it before construction. This does not happen
here because construction is completed before the interlock releases the
lock. The actual creation is protected by a memory barrier using the
"lock()". The assignment also creates a "write" barrier on the ref from
doco I have seen.
Yes, you've got a write memory barrier. You don't have a read one. The
write memory barrier makes sure that everything is written before the
barrier. It doesn't guarantee what order those writes become visible
in.
Only then is the flag set atomically. If we want to be
really sure, we could also add a Thread.MemoryBarrier() instruction before
we open the lock like so:
...
Thread.MemoryBarrier();
Interlocked.Exchange(ref created, 1);
...


You'd need a memory barrier on read as well though - that's what would
make it thread-safe.

To me, this is looking a lot more complicated - and, as we've seen,
debatable in terms of thread-safety - than any of the more common
patterns.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #6

P: n/a
Before getting too far down a path here. Let me ask a related question.
Lets take one of the more common static implemtation as example:
public class Singleton
{
static readonly Singleton instance=new Singleton();
static Singleton()
{
}
Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}

Where is the read barrier here? Ok its executed once and created on first
call to GetInstance() and the instance ref is set to the ref of the object.
So far, so good. However, thread2 on processor2 does not know this and
calls GetInstance() right after thread1. Where is thread2's read barrier
for the instance and instance vars in the object?
Is there an explicit (unseen) read barrier performed on all static vars?

--
William Stacey, MVP

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
William Stacey <st***********@mvps.org> wrote:
Not exactly what happens here. This is not the same as the double checked issue. DCL uses an unsynchronized testing of the object reference.


But that's not the problem with DCL - it then uses a synchronized
testing of the object reference if it was null.

The problem with the DCL is that write-ordering isn't guaranteed unless
you've got a memory barrier, so the reference itself can be written
before object has finished initializing. I don't see anything in your
code to stop a second thread correctly seeing that a first thread is
initializing the object, and then waiting until that initialization is
finished.
So the
ref could be assigned by thread1 and then context switch, then thread2 could get that ref and try to use it before construction. This does not happen here because construction is completed before the interlock releases the
lock. The actual creation is protected by a memory barrier using the
"lock()". The assignment also creates a "write" barrier on the ref from
doco I have seen.


Yes, you've got a write memory barrier. You don't have a read one. The
write memory barrier makes sure that everything is written before the
barrier. It doesn't guarantee what order those writes become visible
in.
Only then is the flag set atomically. If we want to be
really sure, we could also add a Thread.MemoryBarrier() instruction before we open the lock like so:
...
Thread.MemoryBarrier();
Interlocked.Exchange(ref created, 1);
...


You'd need a memory barrier on read as well though - that's what would
make it thread-safe.

To me, this is looking a lot more complicated - and, as we've seen,
debatable in terms of thread-safety - than any of the more common
patterns.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 15 '05 #7

P: n/a
William Stacey [MVP] <st***********@mvps.org> wrote:
Before getting too far down a path here. Let me ask a related question.
Lets take one of the more common static implemtation as example:
public class Singleton
{
static readonly Singleton instance=new Singleton();
static Singleton()
{
}
Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}

Where is the read barrier here?
I believe it's in the check to see that the type is initialized in the
first place, which must happen in its entirety (with a corresponding
write barrier) before the thread gets any further.
Ok its executed once and created on first
call to GetInstance() and the instance ref is set to the ref of the object.
So far, so good. However, thread2 on processor2 does not know this and
calls GetInstance() right after thread1. Where is thread2's read barrier
for the instance and instance vars in the object?
Is there an explicit (unseen) read barrier performed on all static vars?


All static members I believe, yes - at least until the JIT knows that
the type is definitely initialized. (That in itself would presumably
require a single read barrier per thread, but thereafter there's no
need for *another* read barrier.)

That's my understanding of it, but to be honest it *is* a difficult
area.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #8

P: n/a
> All static members I believe, yes - at least until the JIT knows that
the type is definitely initialized. (That in itself would presumably
require a single read barrier per thread, but thereafter there's no
need for *another* read barrier.)


If that is true, then my example would benefit from the same read barrier as
using a static var. No? Agreed this is a gray area (at least for me).

--
William Stacey, MVP

Nov 15 '05 #9

P: n/a
William Stacey [MVP] <st***********@mvps.org> wrote:
All static members I believe, yes - at least until the JIT knows that
the type is definitely initialized. (That in itself would presumably
require a single read barrier per thread, but thereafter there's no
need for *another* read barrier.)


If that is true, then my example would benefit from the same read barrier as
using a static var. No? Agreed this is a gray area (at least for me).


No, because the read barrier could occur before the write barrier which
happens when you exit the monitor. You need the write barrier to occur
before the read barrier, which it does with normal synchronized data
access and with the "simple" singleton.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #10

P: n/a
> No, because the read barrier could occur before the write barrier which
happens when you exit the monitor. You need the write barrier to occur
before the read barrier, which it does with normal synchronized data
access and with the "simple" singleton.


The thread2 can't see ref until thread1 creates the object *and stores the
ref. Then it should benefit from the same read barrier that the other
static design does on read (the one we don't see). The following example
shows a more explicit implementation in respect to the ref var itself. The
ref itself is definitely "barriered" on both reads and writes. My question
now would be the read barrier for the internal fields of the class.
However, I have the same question regarding the static implementation.

public static SingletonClass GetInstance()
{
// If instance already created, ref will not be null, so return instance.
if ( Interlocked.CompareExchange(ref singletonInstance, null, null) !=
null )
return (SingletonClass)singletonInstance;
else
{
lock(syncLock)
{
if ( singletonInstance != null )
return (SingletonClass)singletonInstance;
SingletonClass tmpSC = new SingletonClass();
Interlocked.Exchange(ref singletonInstance, tmpSC);
return (SingletonClass)singletonInstance;
}
}
}

--
William Stacey, MVP

Nov 15 '05 #11

P: n/a
William Stacey [MVP] <st***********@mvps.org> wrote:
No, because the read barrier could occur before the write barrier which
happens when you exit the monitor. You need the write barrier to occur
before the read barrier, which it does with normal synchronized data
access and with the "simple" singleton.
The thread2 can't see ref until thread1 creates the object *and stores the
ref.


Not sure what you mean here. Two threads can both enter the GetInstance
method before anything else happens. At that stage, both threads know
that the type has been initialized, so there needn't be any more read
barriers. The "dodgy" thread can then see assignments in any order so
long as all of the ones before the lock is exited are seen before all
the ones after the lock is exited - I think!
Then it should benefit from the same read barrier that the other
static design does on read (the one we don't see). The following example
shows a more explicit implementation in respect to the ref var itself. The
ref itself is definitely "barriered" on both reads and writes. My question
now would be the read barrier for the internal fields of the class.
However, I have the same question regarding the static implementation.


I think the key thing is that the memory barrier is only incurred until
the thread knows that the type has definitely been initialized.

Unfortunately I don't know anyone on the group with a deeper
understanding of this issue - I'm sure I've got some things wrong, and
I'd like to know what.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #12

P: n/a
> I think the key thing is that the memory barrier is only incurred until
the thread knows that the type has definitely been initialized.


Not beat this into the ground, but it is interesting. Can we assume that
line 2 does not get hit until line 1 is fully created and returns ref to
tmpSC or no?

1) SingletonClass tmpSC = new SingletonClass();
2) return;

--
William Stacey, MVP

Nov 15 '05 #13

P: n/a
William Stacey [MVP] <st***********@mvps.org> wrote:
I think the key thing is that the memory barrier is only incurred until
the thread knows that the type has definitely been initialized.


Not beat this into the ground, but it is interesting. Can we assume that
line 2 does not get hit until line 1 is fully created and returns ref to
tmpSC or no?

1) SingletonClass tmpSC = new SingletonClass();
2) return;


Not sure, to be honest.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 15 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.