Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy singleton in a multithreaded c# application

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 !

like image 523
Anubhav Sharma Avatar asked Mar 05 '13 11:03

Anubhav Sharma


2 Answers

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.

like image 149
Richard Avatar answered Oct 19 '22 19:10

Richard


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;
            }
        }
    }
}
like image 34
David Gregor Avatar answered Oct 19 '22 18:10

David Gregor