Regarding local variable passing in Thread

前端 未结 2 800
北恋
北恋 2020-11-27 07:57

I\'m having a hard time in understanding the unexpected output for the following program:

class ThreadTest
{
     static void Main()
     {
          for(int         


        
相关标签:
2条回答
  • 2020-11-27 08:34

    Yes, threads have their own stacks. But here you also have an issue with variable capture. Try changing the code to:

    class ThreadTest
    {
        static void Main()
        {
             for(int i = 0; i < 10; i++)
             {
                  int j = i;
                  new Thread(() => Console.Write(j)).Start();
             }
        }
    } 
    

    Notice the change in output? Each thread is being started with a reference to the variable, not the value. When I insert the int j = i; line, we are breaking the variable capture. Your unexpected output has less to do with threading than it does closures.

    0 讨论(0)
  • 2020-11-27 08:38

    Each thread gets its own stack. The problem that you are facing has nothing to do with stack. The problem is the way it is generating code for your anonymous delegate. Use tool like refelector to understand the code that it is generating. The following will fix your problem:

    static void Main() 
            {
                for (int i = 0; i < 10; i++)
                {
                    int capture = i;
                    new Thread(() => Console.Write(capture)).Start();
                }
            } 
    

    Under the hood

    Whenever you use a variable from outer scope (in your case variable i) in anonymous delegate, the compiler generates a new class that wraps anonymous function along with the data that it uses from the outer scope. So in your case the generated class contains - one function and data member to capture the value of variable i. The class definition looks something like:

    class SomeClass
    {
        public int i { get; set; }
    
        public void Write()
        {
            Console.WriteLine(i);
        }
    }
    

    The compiler re-writes your code as follows:

    SomeClass someObj = new SomeClass();
    for (int i = 0; i < 10; i++)
    {
        someObj.i = i;
        new Thread(someObj.Write).Start();
    }
    

    and hence the problem - that you are facing. When you capture a variable, the compiler does the following:

    for (int i = 0; i < 10; i++)
    {
        SomeClass someObj = new SomeClass();
        someObj.i = i;
        new Thread(someObj.Write).Start();
    }
    

    Note the difference in SomeClass instantiation. When you capture a variable, it creates as many instances as there are number of iterations. If you do not capture a variable, it tries to use the same instance for all iterations.

    Hope, the above explanation will clarify your doubt.

    Thanks

    0 讨论(0)
提交回复
热议问题