Differing behavior when starting a thread: ParameterizedThreadStart vs. Anonymous Delegate. Why does it matter?

前端 未结 3 1879
臣服心动
臣服心动 2020-12-19 11:39

When I run the code below the output is \"DelegateDisplayIt\", typically repeated 1-4 times. I\'ve run this code probably 100 times, and not once has the output ever been \"

相关标签:
3条回答
  • 2020-12-19 11:49

    Your assumption is correct. The statement parameterizedThread.Start(flag) copies the flag variable at the time of the call.

    By contrast, the anonymous delegate captures the original variable in a closure. The variable isn't copied until the delegate executes the DelegateDisplayIt method. At that point, the value may be true or false, depending on where the original thread is in the calling loop.

    0 讨论(0)
  • 2020-12-19 11:50

    flag is a boolean variable. It is passed by value to the delegate. It will never be true, because the false value is copied and sent to the delegate.

    If you use an anonymous delegate, you'll be implicitly using a closure to access the boolean value.

    In .NET, the compiler constructs an anonymous type to hold the reference for the variable that is the subject of the closure (flag) which both the anonymous delegate and the method will then reference. They will then share the variable, so if one changes it both will see the change.

    This really isn't a threading question, its about pass-by-value and closures. Here's a decent blog post about closures. Pass-by-value is pretty straight forward; if you need to brush up on that I'd suggest buying a copy of CLR Via C# by Jeffrey Richter.

    0 讨论(0)
  • 2020-12-19 12:00

    Let's take the first case:

    for (int i = 0; i < 10; i++)
    {
        bool flag = false;
        new Thread(delegate() { DelegateDisplayIt(flag); }).Start();
        flag = true;
    }
    

    Here when you construct the anonymous delegate the value of flag is false, but when the DelegateDisplayIt method executes, the flag has already been set to true by the next line, and you see the output displayed. Here's another example that illustrates the same concept:

    for (int i = 0; i < 5; i++) 
    {
        ThreadPool.QueueUserWorkItem(state => Console.WriteLine(i));
    }
    

    This will print five times five.

    Now let's take the second case:

    for (int i = 0; i < 10; i++)
    {
        bool flag = false;
        var parameterizedThread = new Thread(ParameterizedDisplayIt);
        parameterizedThread.Start(flag);        
        flag = true;
    }
    

    the value passed to the callback is the one that the variable posses when you call the Start method, which is false and that's why you never see the output in the console.

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