使用具有单个变量名称和线程的两个循环可能会导致奇怪的行为

时间:2018-02-05 11:44:57

标签: c# multithreading

当我使用以下代码时,我遇到了一个奇怪的错误:

            for (int i = 0; i < 10; i++)
            {
                new Thread(() => Console.Write(i)).Start();
            }
            Console.WriteLine();
            for (int i = 0; i < 10; i++)
            {
                var temp = i;
                new Thread(() => Console.Write(temp)).Start();
            }

结果无法预测:

  

444554689

     

100123456789

我不明白为什么在第二个周期中如果我使用临时变量就会出现线程问题。我认为这是由于变量“i”的名称相同,因为当我改变它时,问题就消失了。但它们有不同的范围。

那么,这种行为的原因是什么?

1 个答案:

答案 0 :(得分:1)

你在第二个 for 循环中所做的是 closure ,它允许匿名方法和lambda函数捕获其中的未绑定变量词汇范围。

可能这是每个人引用的最经典的样本:

tr match {
    case test1 @ Test1(str) =>
        str = test1.str + "some another string"
}

示例包含典型错误。新手开发人员认为此代码将输出public void Run() { var actions = new List<Action>(); for (int i = 0; i < 3; i++) actions.Add(() => Console.WriteLine(i)); foreach (var action in actions) action(); } ,但实际上它将输出"0 1 2"。如果您查看此方法的扩展版本,这种奇怪的行为很容易理解:

"3 3 3"

在这种情况下,他们说变量是通过引用循环,而不是通过值循环。许多程序员批评这种封闭的特殊性。他们认为现在还不清楚,对于那些清楚了解 闭包 内部内容的人来说,这是合乎逻辑的。

本网站的代码示例。 Here您可以阅读详细信息。