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

本文关键字:为什么 等待 线程 启动 | 更新日期: 2023-09-27 18:13:23

我一直在尝试线程和任务(.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()方法参数是字符串的值类型。

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

Google "access to modified closure"。发生的事情是,你的局部变量"item"在调用Print函数之前改变了它的值。一种解决方案是在循环作用域中创建一个新变量,并将item赋值给它。

由于c#闭包,该项在创建线程启动时被计算。另一种强制项求值的方法是引入一个变量,这样闭包就会像这样包含它:

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

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

当你使用线程的计时时,你也可以重新排序主线程的计时,所以有时循环将在新线程的print方法运行之前执行,有时在之后执行。

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