Skip to main content

thread safe singleton and parametized threadstart

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 .

Comments

Anonymous said…
Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

Popular posts from this blog

Getting Started with Stateless : A Lightweight Workflow Library Alternative for .NET

Image Credit: https://www.pioneerrx.com A year ago, I was looking for a simple workflow manager for a project I was working. Its a medium sized application that involves tracking the state of assets in the system. Back in 2008, Microsoft (MS) introduced new technologies along with the release of Visual Studio 2008: Windows Presentation Foundation (WPF), Windows Communication Foundation (WCF), and  Windows Workflow Foundation (WF). Having worked in a company utilizing mostly MS products for development, my first option was to go with WF. After doing some time reading and studying the library, I paused and decided it was too complex for my requirement. Using WF would be an overkill and the fact that it has, a rather, steep learning curve, there has to be another option. My mind toyed with the idea of developing a simple workflow library myself. It would be a learning experience but it might end up consuming a lot of time. Why reinvent the wheel? So I started querying the ...

Hiding Unwanted Python Folders and Files in Visual Studio Code

Visual Studio Code is a universal editor and pretty good at it. However, the explorer view maybe cluttered with the automatically generated folders and files confusing developers. Python is no different. Below are example files and folders generated by Python. The __pycache__ folder and *.pyc files  are totally unnecessary to the developer. To hide these files from the explorer view, we need to edit the settings.json for VSCode. Add the folder and the files as shown below: Copy and paste the lines below : "**/*.pyc" : { "when" : "$(basename).py" }, "**/__pycache__" : true

Cyber-bullying : The "good", the bad and the ugly

Image courtesy of http://www.digitalesq.com/ Cyber-bullying is defined as  the willful and repeated use of cell phones, computers, and other electronic communication devices to harass and threaten others. With the advent of social media, the incidents has increased in numbers and the victims does not even know what is hitting them. For the past years, we have heard of  depressions and deaths because of this. Yet, there has never been a strong drive to increase public awareness and promote support groups to help victims outside of the schools.  Campaigns and programs has never gained mainstream presence enough to make an impact.