perhaps the most commonly discussed design pattern in OOP is singleton . just recently , we had a "design pattern" atmosphere in our office (some sort of an atmosphere relating to "resign patterns" lol) . singleton was in the limelight once again and one issue that made it more interesting is dealing with thread safe singleton . questions like : what is two or three threads starts at the same time and realizes that the singleton class is not yet existing , each of the threads will create a new instance of the singleton , thus breaking the main reason why singleton exist in the first place . i kinda got curious of all the solutions that was discussed so i made a little code to test it .
using the singleton design pattern allows the developer to work with only one instance of a class . this avoids the disadvantages of having too many instances of a single class in the memory together with the side effects it may cause in the application .
to start , i created a singleton class that is not threadsafe . creating a singleton class can be done simply by hiding the constructor from the outside by making it private and creating a static method to retrieve the instance . below is the my singleton class :
---------------------
class MySingleton
{
private static MySingleton _instance = null;
private string _instanceName = "Marvin";
public string InstanceName
{
get{ return _instanceName; }
}
private MySingleton(){}
//the GetInstance Method wthout parameter
public static MySingleton GetInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
return _instance;
}
}
---------------------
to test it , i created a tester class with 2 methods to test the two GetInstance methods in my singleton
---------------------
static void Main(string[] args)
{
CreateInstance();
//test the other method
CreateInstanceWithParameter("Test");
Console.ReadKey();
}
static void CreateInstance()
{
//Test singleton without parameter
MySingleton singleton = MySingleton.GetInstance();
Console.WriteLine(singleton.InstanceName);
}
static void CreateInstanceWithParameter(object name)
{
MySingleton singleton = MySingleton.GetInstance((string)name);
Console.WriteLine(singleton.InstanceName);
}
---------------------
running the tester would prove that indeed our singleton works . it prints the instance that was first created which is the one having the name "Marvin" . the creation of another instance with a name "Test" failed .
some of you may ask , why make use of the type object in passing the parameter in the second method . it will all make sense when we will implement the singleton in multithreaded environment . to do these add the following code in your tester class and make sure that you reference System.Threading.
---------------------
static void CreateInstanceWithThreading()
{
ParameterizedThreadStart pts1 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts2 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts3 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts4 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts5 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
Thread t1 = new Thread(pts1);
Thread t2 = new Thread(pts2);
Thread t3 = new Thread(pts3);
Thread t4 = new Thread(pts4);
Thread t5 = new Thread(pts5);
t1.Start("1");
t3.Start("3");
t4.Start("4");
t2.Start("2");
t5.Start("5");
}
---------------------
and update your CreateInstanceWithParameter method to
---------------------
static void CreateInstanceWithParameter(object name)
{
//Test singleton with parameter
MySingleton singleton = MySingleton.GetInstance((string)name);
string timeStamp = DateTime.Now.Millisecond.ToString();
Console.WriteLine("Time :" + timeStamp+" >> TID: "+name.ToString()+" IName: "+
singleton.InstanceName);
}
---------------------
the reason why i made the parameter type object is t support ParametizedThreadStart . this is a new concept in .net 2.0 that allows the thread to call a delegate with parameters . notice the way i called the Thread.Start() method , i passed the parameter needed by the delegate . the timestamp in the output will just give us an idea how the threads started . running the program may give different results . below are some of the results i received :
---------------------
run 1:
Time :0 >> TID: 3 IName: 3
Time :0 >> TID: 2 IName: 2
Time :0 >> TID: 1 IName: 2
Time :0 >> TID: 5 IName: 2
Time :0 >> TID: 4 IName: 2
run 2:
Time :203 >> TID: 3 IName: 3
Time :203 >> TID: 4 IName: 3
Time :203 >> TID: 1 IName: 1
Time :218 >> TID: 2 IName: 1
Time :234 >> TID: 5 IName: 1
---------------------
in run 1 , all the threads started at the same time and two instance of the singleton was created ( 3 and 2) . for the second run , 3 threads started at the same time and created two instance of the singleton (3 and 1) . in some cases only one instance is created . its hard to predict the operation . thus , we need to make the singleton threadsafe .
we can make use of locks or mutex to make sure that onlyone instance is created . by using these mechanishm we only allow a single thread to enter in the critical section at a time , thus , preventing two or more threads creating seperate instances of the singleton . shown below is the code to do it using lock and mutex
--------------------
//using lock:
//declare this
private static object _padlock=new object();
public static MySingleton GetInstance(string instanceName)
{
//lock the critical section
lock (_padlock)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
}
return _instance;
}
--------------------
//using mutex
private static System.Threading.Mutex _mutex =
new System.Threading.Mutex();
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
_mutex.WaitOne();
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
_mutex.ReleaseMutex();
return _instance;
}
--------------------
run 1:
Time :343 >> TID: 3 IName: 1
Time :343 >> TID: 1 IName: 1
Time :375 >> TID: 2 IName: 1
Time :359 >> TID: 4 IName: 1
Time :375 >> TID: 5 IName: 1
run 2:
Time :984 >> TID: 1 IName: 1
Time :984 >> TID: 3 IName: 1
Time :15 >> TID: 4 IName: 1
Time :31 >> TID: 5 IName: 1
Time :15 >> TID: 2 IName: 1
--------------------
both the mutex and lock approach gurantees threadsafe singleton . run 1 simply illustrates how instance 1 got the lock to prevent instance 3 from creating another instance . run 2 demonstrates how instance 1 locked the critical section to prevent instance 3 from creating another instance .
there is however another way of making sure that only one instance is created . instantiate your singleton immediately to make sure that an instance is already running even if no one else is calling it . shown is the code to illustrate this point:
--------------------
class MySingleton
{
private static MySingleton _instance = new MySingleton();
private string _instanceName = "Marvin";
public string InstanceName
{
get
{
return _instanceName;
}
}
private MySingleton()
{
}
//the GetInstance Method wthout parameter
public static MySingleton GetInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
return _instance;
}
}
--------------------
run 1:
Time :812 >> TID: 3 IName: Marvin
Time :812 >> TID: 4 IName: Marvin
Time :812 >> TID: 1 IName: Marvin
Time :843 >> TID: 5 IName: Marvin
Time :812 >> TID: 2 IName: Marvin
--------------------
the output illustrates that even if you call the method GetInstance with a parameter it will still retrun an instance bearing the default instance name "Marvin" . thus , the singleton is threadsafe .
take note that my reason of passing te instance name as a parameter is simply to put a better picture how the instances are created . all of the discussed ways above are acceptable , the choice depends on the developer .
using the singleton design pattern allows the developer to work with only one instance of a class . this avoids the disadvantages of having too many instances of a single class in the memory together with the side effects it may cause in the application .
to start , i created a singleton class that is not threadsafe . creating a singleton class can be done simply by hiding the constructor from the outside by making it private and creating a static method to retrieve the instance . below is the my singleton class :
---------------------
class MySingleton
{
private static MySingleton _instance = null;
private string _instanceName = "Marvin";
public string InstanceName
{
get{ return _instanceName; }
}
private MySingleton(){}
//the GetInstance Method wthout parameter
public static MySingleton GetInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
return _instance;
}
}
---------------------
to test it , i created a tester class with 2 methods to test the two GetInstance methods in my singleton
---------------------
static void Main(string[] args)
{
CreateInstance();
//test the other method
CreateInstanceWithParameter("Test");
Console.ReadKey();
}
static void CreateInstance()
{
//Test singleton without parameter
MySingleton singleton = MySingleton.GetInstance();
Console.WriteLine(singleton.InstanceName);
}
static void CreateInstanceWithParameter(object name)
{
MySingleton singleton = MySingleton.GetInstance((string)name);
Console.WriteLine(singleton.InstanceName);
}
---------------------
running the tester would prove that indeed our singleton works . it prints the instance that was first created which is the one having the name "Marvin" . the creation of another instance with a name "Test" failed .
some of you may ask , why make use of the type object in passing the parameter in the second method . it will all make sense when we will implement the singleton in multithreaded environment . to do these add the following code in your tester class and make sure that you reference System.Threading.
---------------------
static void CreateInstanceWithThreading()
{
ParameterizedThreadStart pts1 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts2 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts3 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts4 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
ParameterizedThreadStart pts5 =
new ParameterizedThreadStart(CreateInstanceWithParameter);
Thread t1 = new Thread(pts1);
Thread t2 = new Thread(pts2);
Thread t3 = new Thread(pts3);
Thread t4 = new Thread(pts4);
Thread t5 = new Thread(pts5);
t1.Start("1");
t3.Start("3");
t4.Start("4");
t2.Start("2");
t5.Start("5");
}
---------------------
and update your CreateInstanceWithParameter method to
---------------------
static void CreateInstanceWithParameter(object name)
{
//Test singleton with parameter
MySingleton singleton = MySingleton.GetInstance((string)name);
string timeStamp = DateTime.Now.Millisecond.ToString();
Console.WriteLine("Time :" + timeStamp+" >> TID: "+name.ToString()+" IName: "+
singleton.InstanceName);
}
---------------------
the reason why i made the parameter type object is t support ParametizedThreadStart . this is a new concept in .net 2.0 that allows the thread to call a delegate with parameters . notice the way i called the Thread.Start() method , i passed the parameter needed by the delegate . the timestamp in the output will just give us an idea how the threads started . running the program may give different results . below are some of the results i received :
---------------------
run 1:
Time :0 >> TID: 3 IName: 3
Time :0 >> TID: 2 IName: 2
Time :0 >> TID: 1 IName: 2
Time :0 >> TID: 5 IName: 2
Time :0 >> TID: 4 IName: 2
run 2:
Time :203 >> TID: 3 IName: 3
Time :203 >> TID: 4 IName: 3
Time :203 >> TID: 1 IName: 1
Time :218 >> TID: 2 IName: 1
Time :234 >> TID: 5 IName: 1
---------------------
in run 1 , all the threads started at the same time and two instance of the singleton was created ( 3 and 2) . for the second run , 3 threads started at the same time and created two instance of the singleton (3 and 1) . in some cases only one instance is created . its hard to predict the operation . thus , we need to make the singleton threadsafe .
we can make use of locks or mutex to make sure that onlyone instance is created . by using these mechanishm we only allow a single thread to enter in the critical section at a time , thus , preventing two or more threads creating seperate instances of the singleton . shown below is the code to do it using lock and mutex
--------------------
//using lock:
//declare this
private static object _padlock=new object();
public static MySingleton GetInstance(string instanceName)
{
//lock the critical section
lock (_padlock)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
}
return _instance;
}
--------------------
//using mutex
private static System.Threading.Mutex _mutex =
new System.Threading.Mutex();
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
_mutex.WaitOne();
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
_mutex.ReleaseMutex();
return _instance;
}
--------------------
run 1:
Time :343 >> TID: 3 IName: 1
Time :343 >> TID: 1 IName: 1
Time :375 >> TID: 2 IName: 1
Time :359 >> TID: 4 IName: 1
Time :375 >> TID: 5 IName: 1
run 2:
Time :984 >> TID: 1 IName: 1
Time :984 >> TID: 3 IName: 1
Time :15 >> TID: 4 IName: 1
Time :31 >> TID: 5 IName: 1
Time :15 >> TID: 2 IName: 1
--------------------
both the mutex and lock approach gurantees threadsafe singleton . run 1 simply illustrates how instance 1 got the lock to prevent instance 3 from creating another instance . run 2 demonstrates how instance 1 locked the critical section to prevent instance 3 from creating another instance .
there is however another way of making sure that only one instance is created . instantiate your singleton immediately to make sure that an instance is already running even if no one else is calling it . shown is the code to illustrate this point:
--------------------
class MySingleton
{
private static MySingleton _instance = new MySingleton();
private string _instanceName = "Marvin";
public string InstanceName
{
get
{
return _instanceName;
}
}
private MySingleton()
{
}
//the GetInstance Method wthout parameter
public static MySingleton GetInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
//the GetInstance Method with parameter
public static MySingleton GetInstance(string instanceName)
{
if (_instance == null)
{
_instance = new MySingleton();
_instance._instanceName = instanceName;
}
return _instance;
}
}
--------------------
run 1:
Time :812 >> TID: 3 IName: Marvin
Time :812 >> TID: 4 IName: Marvin
Time :812 >> TID: 1 IName: Marvin
Time :843 >> TID: 5 IName: Marvin
Time :812 >> TID: 2 IName: Marvin
--------------------
the output illustrates that even if you call the method GetInstance with a parameter it will still retrun an instance bearing the default instance name "Marvin" . thus , the singleton is threadsafe .
take note that my reason of passing te instance name as a parameter is simply to put a better picture how the instances are created . all of the discussed ways above are acceptable , the choice depends on the developer .
Comments
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!