Should this class use data locking for multi threading?

后端 未结 3 1327
名媛妹妹
名媛妹妹 2021-01-21 20:55

I have a class that contains some data and there are many threads use it:

class MyClass
{
    static Dictionary MyData;

    static IEnumerable         


        
3条回答
  •  攒了一身酷
    2021-01-21 21:33

    Yes. You should make the code safe for multithreaded operations. The reason is because it is standard practice to make all static members thread-safe whether you expect the code to be run in multithreaded environment or not. Your current code has a staleness problem. That is one thread may call Reset, but other threads calling Data may never see the change. This can be fixed easily by marking MyData as volatile.

    Update:

    The issue of staleness that I am talking about is related to how the C# and JIT compilers optimize code. For example, consider two threads TA and TB. TA calls MyClass.Data and thus reads the MyData reference while TB changes the MyData reference by calling Reset. The compiler is free to reorder the reads and writes of MyData by lifting them outside of loops, caching them in a CPU register, etc. What this means is that TA might miss a change in MyData if it caches the reference in a CPU register or if TB does not commit its write to main memory immediately.

    This is not just some theoretical problem that rarely occurs in practice. In fact, it is quite easy to demonstrate with the following program. Make sure you compile the code in the Release configuration and run it without the debugger (both are mandatory to reproduce the problem). A cursory glance suggests that this program should terminate in about 1 second, but alas it does not because m_Stop is being cached by the worker thread and never sees that the main thread changed its value to true. The simple fix is mark m_Stop as volatile. You can see my explanation here for information about the concept of memory barriers and the reordering of instructions.

    public class Program
    {
        private static bool m_Stop = false;
    
        public static void Main(string[] args)
        {
            var thread = new Thread(
                () =>
                {
                    int i = 0;
                    Console.WriteLine("begin");
                    while (!m_Stop)
                    {
                        i++;
                    }
                    Console.WriteLine("end");
                });
            thread.Start();
            Thread.Sleep(1000);
            m_Stop = true;
            Console.WriteLine("exit");
        }
    }
    

提交回复
热议问题