1

As per the singleton pattern,

public sealed class Singleton
{
    static Singleton instance=null;

    Singleton()
    {
    }

    public void abc(){
    }

    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

the above is not thread-safe.Two different threads could both have evaluated the test if (instance==null) and found it to be true, then both create instances, which violates the singleton pattern.

Confusion is Instance is static, how this can be null once it is called on UI thread or other threads?

EDIT

I meant to said that once i have called Singleton.Instance.abc(); Singleton.Instance should not be null until it is disposed manually. Right?

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
Pankaj
  • 9,749
  • 32
  • 139
  • 283
  • 2
    The source of your confusion isn't clear unfortunately. Could you elaborate on "Confusion is Instance is static, how this can be null once it is called on UI thread or other threads"? – Ani Dec 25 '11 at 10:37
  • Article on implementing the singleton pattern in C#: http://csharpindepth.com/Articles/General/Singleton.aspx – CodesInChaos Dec 25 '11 at 10:40
  • 2
    But I'd avoid the `Class.Instance` singleton pattern in general, and just tell my IoC container to inject a single instance. – CodesInChaos Dec 25 '11 at 10:41

6 Answers6

5

Control is passed to ThreadA

ThreadA trys to get the Instance, it is found to be null.

Control is passed to ThreadB

ThreadB trys to get the Instance, it is found to be null.

Control is passed to ThreadA

ThreadA instantiates Instance.

Control is passed to ThreadB

ThreadB re-instantiates Instance.

Solution: You an use a static constructor to ensure this doesn't happen.

rfmodulator
  • 3,638
  • 3
  • 18
  • 22
  • +1; I like this better than a sequence diagram (which text books might try to throw at the problem). Nice and readable :) – Merlyn Morgan-Graham Dec 25 '11 at 11:31
  • @MerlynMorgan-Graham I wasn't able to get the formatting I was looking for, still new to SO, feel free to beautify. – rfmodulator Dec 25 '11 at 11:32
  • I like how it is formatted so I'm not sure what I'd be fixing. Here's a reference so hopefully you can get what you were looking for - http://stackoverflow.com/editing-help – Merlyn Morgan-Graham Dec 25 '11 at 11:55
2

You are correct the singleton you shown is not thread safe. The trivial way in making it thread safe is:

public sealed class Singleton
{
    static Singleton instance=null;
    static lockObject = new object();
    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            lock(lockObject)
            {
               if (instance==null)
               {
                   instance = new Singleton();
               }
            }
            return instance;
        }
    }
}

You can write a version thread safe without lock, leveraging how C# uses statics ( http://www.yoda.arachsys.com/csharp/singleton.html )

public sealed class Singleton
{
    static readonly Singleton instance=new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

The last version leverages the fact that static constructors in C# are specified to execute only when an instance of the class is created or a static member is referenced, once per AppDomain.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
2

Edit:

I meant to said that once I have called Singleton.Instance.abc(); Singleton.Instance should not be null until it is disposed manually. Right?

Once a single thread has been used to access the Singleton it will already be initialized, and any threads you kick off after that call can safely access the Singleton without it ever being null.

If you kick off multiple threads that access the Singleton at the same time, and leave your code as-is, you will have a problem. If you don't use thread synchronization (lock) to make sure the if null block is entered only one-thread-at-a-time, then you would have a race condition.

If multiple threads sneak by the if block, then multiple threads would try to initialize instance. This is messy, and it is hard to tell what exactly will happen. One problem is that you could actually get multiple instances, one for each thread that snuck through. Any subsequent calls (after the race condition) would get the last instance created.

This may not be the worst problem you will see, though. There might be even worse problems that cause crashes (not sure). It is best to use thread-safe operations for your Singleton rather than finding out :)

See my original answer below for how to make your Singleton thread-safe:


You can create the instance in a static constructor.

The static constructor will only be called on first access, so you wouldn't need your lazy initialization code.

public sealed class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}

According to the answer to this question, it is guaranteed to be called only once, and is thread safe:

Static constructors are guaranteed to be run only once per application domain, before any instances of a class are created or any static members are accessed. http://msdn.microsoft.com/en-us/library/aa645612.aspx

The implementation shown is thread safe for the initial construction, that is, no locking or null testing is required for constructing the Singleton object. However, this does not mean that any use of the instance will be synchronised. There are a variety of ways that this can be done; I've shown one below.

Community
  • 1
  • 1
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • `though you would still need thread synchronization` I don't think so. – CodesInChaos Dec 25 '11 at 10:42
  • @CodeInChaos: Was still solidifying my answer with research. Fixed now :) You'd still might need synchronization for *use* of the object instance, but you wouldn't need synchronization for the constructor. – Merlyn Morgan-Graham Dec 25 '11 at 10:46
  • Your answer doesn't address the root of the OP's confusion. – rfmodulator Dec 25 '11 at 10:53
  • @rfmodulator: Just caught the line "I meant to said that once i have called Singleton.Instance.abc(); Singleton.Instance should not be null until it is disposed manually. Right?" - edited to address that. Let me know if this doesn't correct the problem. – Merlyn Morgan-Graham Dec 25 '11 at 11:06
0

Mr Skeet has an article about this on his website.

http://csharpindepth.com/Articles/General/Singleton.aspx

EDIT

Ok, so the question has been asked, how can a static call create 2 instances when static means there's only 1.

When executing on separate threads the code is shared, but the state of the code isn't. In this case it's the execution stack that's important. Here's an example.

Thread 1 and Thread 2 both execute the Instance getter at the same time.

Thread 1 evaluates if (instance==null) as true and branches into the if code.
Thread 2 evaluates if (instance==null) as true and branches into the if code.

Thread 1 now sets instance to a new Singleton object.
Thread 1 then returns instance.

Thread 2 now sets instance to a new Singleton object. Remember, thread 2 had already evaluated the condition earlier and had branched into this code.
Thread 2 then returns instance.

In this scenario we have returned 2 instances of Singleton.

Cameron MacFarland
  • 70,676
  • 20
  • 104
  • 133
  • My question starts here. How can the static instance becomes null until it is set to null manually? Either it is created on UI threar or any other thread? – Pankaj Dec 25 '11 at 10:42
  • @StackOverflowUser The issue is that `Instance` **begins** as `null` – rfmodulator Dec 25 '11 at 11:34
0

There's only one moment where it won't be thread-safe: If it's called in two different threads running at the same time while not being initialized before.

Both threads will run Instance() and then it might happen that both evaluate instance==null before either one is able to assign the new reference.

To avoid this, use Shadow Wizard's approach or ensure it's called once before you start multiple threads (which, of course, is a lot more complicated and error prone).

Mario
  • 35,726
  • 5
  • 62
  • 78
  • I didn't downvote. But I'd expand this - "which, of course, is a lot more complicated and error prone". It is more like: The program's requirements might change later, and it may not be obvious to maintenance programmers that you're using the call-`Instance`-once-before-multithreading as a hack to work around the fact that the code isn't thread safe. – Merlyn Morgan-Graham Dec 25 '11 at 11:18
-1

Your example is not thread safe, but the probability of actually getting a race condition is very slim, so in many cases it would not matter.

If thread 1 evaluates instance, and thread 2 follows right behind, and evaluates instance before thread 1 has completed creating the singleton object and assigned it to instance, thread 2 will still create a new object, and assign it to instance.

Since the most common use case for a singleton is some sort of settings or configuration object, this will not matter (it will not cause your application to fail). There are other use cases though, where it could matter.

Edit: In answer to your edit: The first instance can be disposed by the GC once thread 2 created the second instance and assigned it to the instance variable of your singleton class, since then the first instance will not be referenced by your application any more.

Treb
  • 19,903
  • 7
  • 54
  • 87
  • can you give any example for this? i tried to use below code and instance persists memory. System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(Singleton.Instance.abc)); t.Start(); System.Threading.Thread t1 = new System.Threading.Thread(new System.Threading.ThreadStart(Singleton.Instance.abc)); t1.Start(); – Pankaj Dec 25 '11 at 10:45
  • @StackOverflow User: There is no way to predict when the garbage collection will collect an object and free it's memory. It is quite possible that the object will persist for quite some time afterwards. You could try to start a GC run manually, and see id the object still persists afterwards. – Treb Dec 25 '11 at 10:52
  • -1 "but the probability of actually getting a race condition is very slim, so in many cases it would not matter." Wrong, It always matters. – rfmodulator Dec 25 '11 at 11:15
  • 2
    @rfmodulator: It doesn't always matter. E.g. an app that isn't multi-threaded. Cost-benefit ratio should be applied here, as it should with every bug. However in this case it is very easy: The cost to making Singleton initialization thread-safe is simply the cost of learning how to do it once, which takes 5 minutes or less. Though the cost of implementing it is so low that once you learn how, you should always apply it to future-proof your app, even if it isn't multi-threaded. Sometimes deploying a fix to an existing app is a huge and unneeded cost - so "it always matters" isn't correct. – Merlyn Morgan-Graham Dec 25 '11 at 11:24
  • @rfmodulator: Though I highly agree with the argument against probability. If the bug can happen, it will happen. – Merlyn Morgan-Graham Dec 25 '11 at 11:26
  • @MerlynMorgan-Graham again, If it's not ALWAYS thread-safe, then it's NEVER thread-safe. Therefore, it always matters. This is the very essence of thread-safety. We could, infact, in alot of situations say "in many cases it would not matter". So you understand the delima, right? – rfmodulator Dec 25 '11 at 11:28
  • @MerlynMorgan-Graham "an app that isn't mutli-threaded" is irrelevant and would be addressed in a differnt post. :) – rfmodulator Dec 25 '11 at 11:39
  • @rfmodulator: Yes. I'm just saying that a blanket statement in either direction could mislead someone. They might never apply a fix or examine their code for bug potential (if they followed advice in this answer). Or they might always apply a fix, even if it is unnecessary and costly to deploy (if they followed the "it always matters" advice). My point is not relevant to the OP, but is relevant to the blanket statements which were made in this thread. – Merlyn Morgan-Graham Dec 25 '11 at 11:48