Lazy singleton in a multithreaded c# application
Solution 1
According to Microsoft's Lazy Initialization documentation, under the section titled "Thread-Safe Initialization":
By default, Lazy objects are thread-safe.
With this in mind, your abc
field needn't be static. As you're using a Lazy<T>
to instantiate your singleton, it's safe to initialise your connection in the CLazySingleton
constructor.
Solution 2
Simple use ThreadSafetyMode
Lazy<MergeSort> ty = new Lazy<MergeSort>(LazyThreadSafetyMode.ExecutionAndPublication);
Solution 3
Would this code be able to take care of multiple threads trying to get the instance at the same time ?
In your scenario can be the "abc" field initialized twice. Imagine situation, that "abc" variable is null. First thread will be inside the "lock" block before the value assignment. Second thread will be waiting before the lock. So the first thread will initialize the "abc" and second thread will reinitialize it (your check for null is outside of lock, that's the reason). But maybe this is not something you should be afraid of.
Can I have a better solution for this ?
Yes you can. Let me describe it in the last block of this answer.
Do I need to use 'lock' here or using Lazy approach takes care of multithreads trying to get the instance ?
Creation of the Value property in Lazy class is thread safe. In your scenario I would use the advantage of property IsValueCreated of Lazy<> class. You will still need the ThreadLock object as well. Just one more thing is, that once you access Value property of Lazy<> class, IsValueCreated property will return true (that's the trick ;-) )
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LazySingleton
{
public class CLazySingleton
{
private static readonly Lazy<CLazySingleton> _instance
= new Lazy<CLazySingleton>(() => new CLazySingleton());
private static readonly object ThreadLock = new object();
public static string abc;
//I will use the service connection object in place of 'abc' in the application
//assume that 'abc' is storing the connection object
private CLazySingleton()
{ }
public static CLazySingleton Instance
{
get
{
if (_instance.IsValueCreated)
{
return _instance.Value;
}
lock (ThreadLock)
{
if (abc == null)
{
abc = "Connection stored in this variable";
Console.WriteLine("Connection Made successfully");
}
}
return _instance.Value;
}
}
}
}
Anubhav Sharma
Updated on April 23, 2020Comments
-
Anubhav Sharma about 4 years
I am working on a multithreaded c# application which is consuming a WCF web service. The connection to the webservice will have a specific timeout which we can define and after which it will close. I am looking to store the connection to the web service using singleton class. I am trying to get the instance as follows :
CLazySingleton ins = CLazySingleton.Instance; string connection = CLazySingleton.abc;
Below is the code for the singleton class :
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LazySingleton { public class CLazySingleton { private static readonly Lazy<CLazySingleton> _instance = new Lazy<CLazySingleton>(() => new CLazySingleton()); private static readonly object ThreadLock = new object(); public static string abc; //I will use the service connection object in place of 'abc' in the application //assume that 'abc' is storing the connection object private CLazySingleton() { } public static CLazySingleton Instance { get { if (abc == null) { lock (ThreadLock) { //Make the connection abc = "Connection stored in this variable"; Console.WriteLine("Connection Made successfully"); return _instance.Value; } } else { return _instance.Value; } } } } }
My questions are : 1. Would this code be able to take care of multiple threads trying to get the instance at the same time ? This is currently my biggest concern. 2. Can I have a better solution for this ? 3. Do I need to use 'lock' here or using Lazy approach takes care of multithreads trying to get the instance ?
Any help would be appreciated.
Thanks !
-
Phil about 11 yearsLazy's default constructor uses LazyThreadSafetyMode.ExecutionAndPublication, it's thread safe by default.
-
Anubhav Sharma about 11 yearsHi Richard, Thanks for the response. You made a good point. Even I was pondering upon the same. But my question is, if I write the logic to make the connection in the constructor, how would I manage the scenario where the connection gets expired by itself after specified timeout. In that case, the field abc will become null and the singleton class would keep on returning that as null only as the constructor won't be called again. I hope that I could deliver my point.
-
Anubhav Sharma about 11 yearsThanks, I'll surely try this.
-
thewpfguy about 11 yearsI think using Singleton is not the right pattern here, actually you do not need to manage your connection this way. And, are you sure you are calling a web service, because what's the kind of timeout you mention here?