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

本文关键字:线程 启动 方法 值传 创建 循环 | 更新日期: 2023-09-27 18:12:00

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

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

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

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

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

一个经典的闭包和捕获变量问题,每个新人都必须问。

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

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

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

解决这个问题的方法是将该变量复制到一个新的变量中,然后捕获新变量。通过在循环中声明它,每次迭代都会生成一个新的,因为循环的内部作用域在迭代之间是不共享的。

请注意,类似的问题也适用于。net 4.0及更早版本的foreach循环中的capture变量,但在4.5及以上版本中已修复。

我如何确保在线程启动值的时候传递给GetEndToEndRequestProcessTime()时提供的相同线程被创建了?

答案:通过创建一个本地副本来记住i的值,当执行命令给这个任务/线程时,然后传递这个本地副本。

确切问题:当你启动你的任务/线程时,i的值已经改变,因此你的执行是意外的