在循环中创建线程时,将值传递给c#中的线程启动方法

时间:2015-09-08 19:05:10

标签: c# multithreading

我在循环中创建线程,我需要在线程启动方法中传递循环计数器(就像创建线程时一样)。

for (int i = 0; i < ListSize; i++)
{
    thread = new Thread(() => 
        Helper.GetEndToEndRequestProcessTime(EmailList[i], reqResultData, i, ListSize));
    workerThreads.Add(thread);
    thread.Start();
}

在上面的示例中,i是变量I作为GetEndToEndRequestProcessTime()中的参数。但问题是当实际线程的起始值i正在发生变化时,我在GetEndToEndRequestProcessTime()得到了错误的结果。

如何确保在线程启动时传递给GetEndToEndRequestProcessTime()的值与创建线程时提供的值相同。

3 个答案:

答案 0 :(得分:5)

每个新手必须要问的经典闭包和捕获变量问题。

for (int i = 0; i < ListSize; i++)
{
    var j = i;
    thread = new Thread(() => Helper.GetEndToEndRequestProcessTime(EmailList[j], reqResultData, j, ListSize));
    workerThreads.Add(thread);
    thread.Start();
}

更多信息:http://csharpindepth.com/articles/chapter5/closures.aspx

答案 1 :(得分:2)

如上所述,这里的问题是闭包问题。

这意味着因为您只为i分配了一个变量,当您通过在new Thread(() => ...)中引用它来捕获它时,您实际上正在复制变量的地址。因此,当变量为下一个循环递增时,第一个thread中正在进行的操作将获得更新的值,因为它都指向i的单个值。

解决此问题的方法是将变量复制到新变量中,然后捕获新变量。通过在循环中声明它,将为每次迭代创建一个新的迭代,因为循环的内部范围不在迭代之间共享。

注意类似的问题适用于.NET 4.0及更早版本的foreach循环中的捕获变量,但在4.5及更高版本中已修复。

答案 2 :(得分:1)

  

如何在线程启动值时确保   传递给GetEndToEndRequestProcessTime()与提供时相同   线程是否已创建?

答案:通过创建一个本地副本,该副本将记住当执行的命令被赋予此任务/线程然后传递此本地副本时i的值是什么。 / p>

确切问题:当您启动任务/线程时,i的值已更改,因此您的执行意外。