启动多个线程,你为什么要等?

时间:2011-11-01 12:37:52

标签: c# multithreading task

我一直在玩线程和任务(.net 4)并注意到一些奇怪的行为,当你启动多个线程而不等待每个线程启动调用之间几毫秒。

运行时的以下示例不会输出我的预期:

1
2
1
2

但是只输出:

2
2
2
2

以下是我正在运行的代码。

public static void Main()
{
    var items = new[] {"1", "2"};
    foreach (var item in items)
    {
      var thread = new Thread(() => Print(item));          
      thread.Start();
      //var task = Task.Factory.StartNew(() => Print(item));               
    }
}

static void Print(string something)
{
  while (true)
  {
    Console.WriteLine(something);
    Thread.Sleep(1000);
  }
}

现在,当我在thread.Start()之后调用Thread.Sleep(50)时,输出只会按预期显示

1
2
1
2

我的问题是:

  • 为什么当您在两个线程之间不等待时,请执行第一个操作 线程松开你最初启动它的方法的参数值?

即。使用参数“1”启动第一个线程,使用参数“2”启动第二个线程,但是第一个线程的参数也变为“2”?这没有任何意义,特别是因为Print()方法参数是字符串的值类型。

4 个答案:

答案 0 :(得分:5)

Google“访问修改后的关闭”。发生了什么事情是你的局部变量“item”在调用Print函数之前更改了它的值。解决方案是在循环范围内创建一个新变量并为其分配项目。

答案 1 :(得分:2)

在您创建的线程由于c#闭包而启动时,将评估该项目。强制项目评估的另一种方法是引入一个变量,以便闭包将包含它:

foreach (var item in items)     
        {
            var closedItem = item;
            var thread = new Thread(() => Print(closedItem));                 
            thread.Start();       
        } 

答案 2 :(得分:1)

你的问题不在于线程。你的问题在于封闭和foreach。你可以在这里阅读原因: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

当您使用线程的时间时,您也会对主线程的时间进行重新排序,因此有时循环将在新线程的print方法运行之前执行,有时也会在之后执行。

答案 3 :(得分:0)

向我们展示线程启动代码,你会发现你没有传递一个常量字符串而是一个引用变量,并且在调用那些Start方法之间你可能正在改变变量。