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?
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With