Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are C# static class private fields thread safe?

I have a C# static class accessed from multiple threads. Two questions:

  1. Are my private static fields thread safe when the field is initialized on declaration?
  2. Should I lock when creating private static fields from within static constructor?

Usage of static class from different threads:

class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                Task.Run(() =>
                {
                    string name = MyStaticClass.GetValue(9555);
                    //...
                });
            }
        }
}

Option 1 of static class:

public static class MyStaticClass
    {
        private static MyClass _myClass = new MyClass();

        public static string GetValue(int key)
        {
            return _myClass.GetValue(key);
        }
    }

Option 2 of static class:

public static class MyStaticClass
    {
        private static MyClass _myClass;
        private static object _lockObj = new object();

        static MyStaticClass()
        {
            InitMyClass();
        }

        private static void InitMyClass()
        {
            if (_myClass == null)
            {
                lock(_lockObj)
                {
                    if (_myClass == null)
                    {
                        _myClass = new MyClass();
                    }
                }
            }
        }

        public static string GetValue(int key)
        {
            return _myClass.GetValue(key);
        }
    }

Instance class created from the static class:

public class MyClass
    {
        private Dictionary<int, Guid> _valuesDict = new Dictionary<int, Guid>();

        public MyClass()
        {
            for (int i = 0; i < 10000; i++)
            {
                _valuesDict.Add(i, Guid.NewGuid());
            }
        }

        public string GetValue(int key)
        {
            if (_valuesDict.TryGetValue(key, out Guid value))
            {
                return value.ToString();
            }

            return string.Empty;
        }
    }
like image 218
Yevgeny Granat Avatar asked Dec 20 '18 13:12

Yevgeny Granat


2 Answers

Should I lock when initializing private static fields from within static constructor?

Let's not bury the lede here:

Never lock in a static constructor. Static constructors are already locked by the framework so that they run on one thread exactly once.

This is a special case of a more general bit of good advice: never do anything fancy with threads in a static constructor. The fact that static constructors are effectively locked, and that lock can be contested by any code that accesses your type, means that you can very quickly get into deadlocks that you did not expect and are hard to see. I give an example here: https://ericlippert.com/2013/01/31/the-no-lock-deadlock/

If you want lazy initialization, use the Lazy<T> construct; it was written by experts who know how to make it safe.

Are my private static fields thread safe when the field is initialized on declaration?

Thread safety is the preservation of program invariants when program elements are called from multiple threads. You haven't said what your invariants are, so it is impossible to say if your program is "safe".

If the invariant you are worried about is that the static constructor is observed to run before the first static method is executed, or the first instance is created, of a type, C# guarantees that. Of course, if you write crazy code in your static constructor, then crazy things can happen, so again, try to keep your static constructors very simple.

like image 51
Eric Lippert Avatar answered Sep 17 '22 21:09

Eric Lippert


fields of static class are not thread safe by default and should avoid unless it is just for read purpose. Here down side is "lock" as well, it will create serialized processing in multi threaded environment.

public static class MyStaticClass
{
    private static MyClass _myClass;
    private static object _lockObj;

    static MyStaticClass()
    {
           _myClass = new MyClass();
           _lockObj = new object();
    }

    public static string GetValue(int key)
    {
        return _myClass.GetValue(key);
    }
    public static void SetValue(int key)
    {
        lock(_lockObj)
        {           
             _myClass.SetValue(key);
        }
    }
}
like image 35
mbshambharkar Avatar answered Sep 18 '22 21:09

mbshambharkar