Search code examples
c#stack

In c#, why is local variable of value type shared by different threads


I understand that the value type is stored in the stack area memory, except for some situations, such as the value type included as a reference type field member.

And I know that threads have different unique stack areas.

However, code execution results show that the a, b, and c threads share the count variable and increase the value to 300.

What's wrong?

                public void Test()
        {
            int count = 0;
            Thread a = new Thread(delegate ()
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine($"Thread ID : {Thread.CurrentThread.ManagedThreadId}, Count : {++count}");
                }
            });
            a.Start();

            Thread b = new Thread(delegate ()
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine($"Thread ID : {Thread.CurrentThread.ManagedThreadId}, Count : {++count}");
                }
            });
            b.Start();

            Thread c = new Thread(delegate ()
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine($"Thread ID : {Thread.CurrentThread.ManagedThreadId}, Count : {++count}");
                }
            });
            c.Start();
        }

enter image description here


Solution

  • I understand that the value type is stored in the stack area memory, except for some situations, such as the value type included as a reference type field member.

    In this case, count is a captured variable, which the compiler implements precisely by making it a field on an object on the heap. You can see this by compiling and decompiling the code, like this - in particular:

        [CompilerGenerated]
        private sealed class <>c__DisplayClass0_0
        {
            public int count;
    

    This is how the compiler achieves the required semantic of the value being shared between all delegate usages - which in this case happens to mean "between threads" (although that isn't a necessary part).