by Ahmed
16. November 2006 10:57
The Singleton is a very common and simple design pattern. Its used in situations where only one instance is required to serve multiple client requests. Here is a simple implementation of a Singleton:
class NTSSingleton
{
private static NTSSingleton singleton;
private NTSSingleton()
{
// Perform some operation here
}
public static NTSSingleton GetInstance()
{
if (singleton == null)
{
singleton = new NTSSingleton();
}
return singleton;
}
}
The implementation is pretty straight forward and will work in most cases however its not thread-safe. Lets say that concurrent requests try to reference the Singleton for the first time (this can potentially happen in IIS6 when the ASP.NET worker process is recycled, if idle for some time, and suddenly multiple requests come in). In such a scenario multiple instances of the NTSSingleton will actually be returned to requesting threads and this of course contradicts the idea behind the singleton, not to mention the additional memory that will be consumed.
Of course, the above Singleton could be made thread safe by making some modifications. But by using static constructors this job becomes so much easier. Static constructors are basically used to initialize static variables and are executed by the runtime before executing any other member code. Following is another implementation of a Singleton using a static constructor.
class TSSingleton
{
private static TSSingleton tsSingleton;
static TSSingleton()
{
tsSingleton = new TSSingleton();
}
private TSSingleton()
{
// Perform some operation here
}
public static TSSingleton GetInstance()
{
return tsSingleton;
}
}
Because the runtime guarantees executing the code in the static constructor before any thing else on that object regardless of the number of the members invoked concurrently, it really helps in building a better Singleton without writing any special code to make it thread safe.
I wrote a quick console application to test both the Singleton implementations for thread safety. The main test method simulates concurrent requests that call the GetInstance() method. It accepts 2 parameters - requests and getInstDlgt. The requests parameter indicates the number of concurrent requests to invoke and the getInsDlgt is a delegate for the GetInstance method that could be either the NTSSingleton.GetInstance or the TSSingleton.GetInstance method.
static void TestSingleton(int requests, GetInstanceDelegate getInsDlgt)
{
object sngltn;
IAsyncResult[] asyncRslts = new IAsyncResult[requests];
WaitHandle[] waitHandles = new WaitHandle[requests];
for (int i = 0; i < requests; i++)
{
asyncRslts[ i ] = getInsDlgt.BeginInvoke(null, null);
waitHandles[ i ] = asyncRslts[ i ].AsyncWaitHandle;
}
// Wait for all concurrent requests to complete
WaitHandle.WaitAll(waitHandles);
// Traverse the returned references
for (int i = 0; i < requests; i++)
{
sngltn = getInsDlgt.EndInvoke(asyncRslts[ i ]);
Console.WriteLine("Singleton ID: {0}", sngltn.GetHashCode());
}
}
For the purpose of this test I also made the private instance constructor of each Singleton version sleep for 2 seconds. Here is the output:
As we can see, the non thread-safe implementation initializes the Singleton multiple times and returns multiple references (indicated by the Singleton obj IDs) to the calling threads where as the thread-safe version executes the static constructor and then executes the GetInstance method at which point the Singleton has already been initialized. The test app can be downloaded from here.
There are a few things to keep in mind regarding static constructors:
- No access modifiers (private or public) can be used as C# assigns it private access
- It can only access static members
- It can't accept any parameters or call other constructors
To read up on various other C# implemenations of a Singleton check out this
article.