Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safe Singleton: why the memory model does not guarantee that the new instance will be seen by other threads?

I have read in Jon's Skeet online page about how to create a thread safe Singleton in C#

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

// Bad code! Do not use!
public sealed class Singleton
{
    private static Singleton instance=null;

    private Singleton()
    {
    }

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

in the paragraph below this code it says:

As hinted at before, 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. Note that in fact the instance may already have been created before the expression is evaluated, but the memory model doesn't guarantee that the new value of instance will be seen by other threads unless suitable memory barriers have been passed.

Can you please explain why doesn't the memory model does not guarantee that the new value of instance will be seen by other threads?

the static variable is located on the heap, but why it is not shared with other threads immediately? do we need to wait for the context switch so the other thread will know the instance is not null anymore?

like image 462
Gilad Avatar asked Dec 14 '17 15:12

Gilad


People also ask

Why is singleton pattern not thread-safe?

A singleton class itself is not thread safe. Multiple threads can access the singleton same time and create multiple objects, violating the singleton concept. The singleton may also return a reference to a partially initialized object.

Is singleton instance thread-safe?

Thread Safe Singleton: A thread safe singleton is created so that singleton property is maintained even in multithreaded environment. To make a singleton class thread safe, getInstance() method is made synchronized so that multiple threads can't access it simultaneously.

How do you ensure thread safety in singleton?

Thread Safe Singleton in JavaCreate the private constructor to avoid any new object creation with new operator. Declare a private static instance of the same class. Provide a public static method that will return the singleton class instance variable.

What happens when two threads access singleton at same time?

Now coming to your question: if you share your singleton object among multiple threads and access it concurrently, every single thread will execute Singleton object's portion of code, wrapped in its own execution.


2 Answers

Can you please explain why doesn't the memory model does not guarantee that the new value of instance will be seen by other threads?

The memory model is complex and not terribly clearly documented at the moment, but fundamentally there are very few situations where it's safe to rely on a value that's written by one thread being "seen" on another thread without either some locking or other inter-thread communication going on.

For example, consider this:

// Bad code, do not use
public class BigLoop
{
    private static bool keepRunning = true;

    public void TightLoop()
    {
        while (keepRunning)
        {
        }
    }

    public void Stop()
    {
        keepRunning = false;
    }
}

If you created two threads, one of which calls TightLoop and another of which calls Stop, there's no guarantee that the looping method will ever terminate.

There are lots of levels of caching in modern CPUs, and requiring that every read goes back to main memory would remove a lot of optimizations. So we have memory models which make guarantees about which changes will definitely be visible in what situations. Other than those guarantees, the JIT compiler is allowed to assume that there's effectively only a single thread - so it could cache the value of the field in a register, and never hit main memory again, for example.

The currently-documented memory model is woefully inadequate, and would suggest that some clearly-weird optimizations should be valid. I wouldn't go too far down that route, but it's worth reading Joe Duffy's blog post on the CLR 2.0 memory model. (That's stronger than the documented ECMA memory model, but a blog post isn't the ideal place for such a key piece of documentation, and I think more clarity is still needed.)

The static variable is located on the heap, but why it is not shared with other threads?

It is shared with other threads - but the value won't necessarily immediately be visible.

like image 125
Jon Skeet Avatar answered Sep 23 '22 02:09

Jon Skeet


Can you please explain why doesn't the memory model does not guarantee that the new value of instance will be seen by other threads?

There are a few problems with that code. Because there isn't a new value assigned to the variable just yet. There are quite some things that can happen between comparing for null (if (instance==null)) and the assignment of the new value (instance = new Singleton();).

The problem you reference is about memory that is cached by the processor, the variable is still null there, but already set in memory by the assignment from the code. It will update that cached memory later on.

like image 27
Patrick Hofman Avatar answered Sep 24 '22 02:09

Patrick Hofman