我正在尝试为某些处理生成不同的线程。我对每个线程中的一些逻辑使用for
循环索引
如何在下面的代码中获得不同的线程来打印1,2,3,4,5?每次我运行它,我得到不同的数字作为输出 - 3,3,3,4,6,6& 2,2,3,5,5,6等
我尝试使用锁定对象,但它没有正确执行。任何人都可以帮我解决这个问题。我只是想确保每个线程/任务获得正确的索引。请注意,每个任务都被强制在单独的线程上运行。
List<Task> tasks1 = new List<Task>();
for (int j = 1; j <= 5; j++)
{
tasks1.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(j);
}
, new CancellationToken()
, TaskCreationOptions.LongRunning
, TaskScheduler.Default)
);
}
Task.WaitAll(tasks1.ToArray());
Console.Read();
答案 0 :(得分:4)
你正在'捕获循环变量'。在lambda中使用j
的事实意味着编译器将以不同的方式对待它(实质上,它将被装箱)并且所有线程将使用相同的共享变量。
简短修复:
for (int j = 1; j <= 5; j++)
{
int jCopy = j;
tasks1.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(jCopy);
}, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default)
);
}
答案 1 :(得分:3)
只是为了完成其他答案。在C#5.0(.NET 4.5)中,关闭foreach
循环变量有一个重大变化,但是没有关闭for
循环变量。
查看Eric [{3}}及其Lippert. Closing over the loop variable considered harmful
中的详细信息(以及前言更新说明)请注意,此问题与多线程或TPL(任务并行库)的使用无关。
其他答案和评论提到它之前已经讨论过,但没有链接到任何先前的答案。以下是一些,为了相互联系:
答案 2 :(得分:2)
回答了数百万次。它与闭包有关。更改您的代码如下
for (int j = 1; j <= 5; j++)
{
int temp = j;
tasks1.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(temp);
}, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default)
);
}
我建议您阅读:Loop variables and Closures