C# Singleton Pattern Designs for ThreadStatic
Asked Answered
F

2

5

I want to figure out about singleton pattern designs. I want to create seperated instances for per thread from my singleton class. So I provided two designs below.

It is Working

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Console.ReadLine();
    }
}
public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance;

    public static SingletonClass Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new SingletonClass();
            }
            return _instance;
        }
    }
    private SingletonClass()
    {

    }
}

It is not working (Throwing NullReferenceException and instance is not being created.)

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Console.ReadLine();
    }
}
public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance = new SingletonClass();

    public static SingletonClass Instance
    {
        get
        {
            return _instance;
        }
    }
    private SingletonClass()
    {

    }
}

I am really wondering why an instance is not created for second design. Can anybody explain that please ?

Forefend answered 11/11, 2017 at 14:12 Comment(7)
The C# compiler generates a static constructor in order to implement the initialization for the variable. The CLR provides a hard guarantee that it only runs once. You need that new statement to run more than once.Numerous
I believe, even if this worked or you got it to work, this is no longer a singleton. A singleton should be single not single per thread.Pinch
CodingYoshi nowhere in the description of singleton does it state it can't be per thread. In other languages ex. D it would be perfectly normal for it to be per thread. Since everything is thread-local by default there.Recognition
@Recognition Agree. But nowhere does it state it cannot be per class, so I will just make sure a class has a single instance of an object and call it the singleton pattern. How would that help? Maybe I will just have a single instance per object then...I think calling it a Singleton would throw people off in C# and this question is about C# not D.Pinch
Please tell me where in C#'s language specification it says that singleton cannot be per thread? As far as I'm aware there's no specification on singleton not being able to be per thread in C#; in fact I'm almost positive that it's not even a part of its language specification. Although per-thread singleton is a common pattern between multiple languages eg. C++ - drdobbs.com/a-per-thread-singleton-class/184401516Recognition
@Recognition It does not say that anywhere in c# specs and I am not making that claim. I am just saying that in .net and C# world I have not seen it. I dont like it but you do. Thats fine.Pinch
Well it's a pattern that's useful for thread-safety as you can avoid synchronization.Recognition
G
3

The answer to your question is mostly related to how class fields are initialized.

In the second example, the _instance field is initialized at declaration. Every time a static field is initialized at declaration, a static constructor will be created (if you don't have it declared already). At compile time, the initialization will be moved into the static constructor. This means that you will end up having something like this (didn't copy the IL code as it would be harder to understand):

public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance;

    public static SingletonClass Instance
    {
        get
        {
            return _instance;
        }
    }
    static SingletonClass()
    {
        _instance = new SingletonClass();
    }
}

The CLR ensures that the static constructor is called only once, regardless of how many threads you have. Looking at the above code, it means that for the two Tasks that you created, the _instance field will be initialized only once (since there will be only one call to the static constructor).

Goldbrick answered 11/11, 2017 at 17:57 Comment(0)
R
4

Instead of using [ThreadStatic] then you could use ThreadLocal<T> which will essentially achieve what you're trying with [ThreadStatic].

public sealed class SingletonClass
{
    private static ThreadLocal<SingletonClass> _instance;

    static SingletonClass()
    {
        _instance = new ThreadLocal<SingletonClass>(() => new SingletonClass());
    }

    public static SingletonClass Instance
    {
        get
        {
            return _instance.Value;
        }
    }

    private SingletonClass()
    {

    }
}

See: https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx for more information.

Edit: To answer your question.

In C# when doing:

private static SingletonClass _instance = new SingletonClass();

Regardless if it's marked with [ThreadStatic] or not then it will only create a single static constructor which sets the instance of SingletonClass.

C# does not have the ability to create static constructors per threads.

That's what you can use ThreadLocal<T> for. If we take your code as an example then the default constructor for SingletonClass essentially becomes the "thread-static" constructor.

Recognition answered 11/11, 2017 at 14:26 Comment(4)
This provides an alternative but does not answer the question.Pinch
Updated my answerRecognition
Thank you, I think, it is a good alternative for nested threads. I will edit my project code with ThreadLocal. But still I want to figure out my question.Forefend
beware, if you are using async/await you may get unexpected or irrelevant instances, because before and after await, thread may change hence the instance you are working on will change. @RainmanOmnibus
G
3

The answer to your question is mostly related to how class fields are initialized.

In the second example, the _instance field is initialized at declaration. Every time a static field is initialized at declaration, a static constructor will be created (if you don't have it declared already). At compile time, the initialization will be moved into the static constructor. This means that you will end up having something like this (didn't copy the IL code as it would be harder to understand):

public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance;

    public static SingletonClass Instance
    {
        get
        {
            return _instance;
        }
    }
    static SingletonClass()
    {
        _instance = new SingletonClass();
    }
}

The CLR ensures that the static constructor is called only once, regardless of how many threads you have. Looking at the above code, it means that for the two Tasks that you created, the _instance field will be initialized only once (since there will be only one call to the static constructor).

Goldbrick answered 11/11, 2017 at 17:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.