multithreading重入问题

我正在尝试为某些处理生成不同的线程。 我for每个线程中的一些逻辑使用for循环索引。
如何在下面的代码中获取不同的线程来打印1,2,3,4,5? 每次我运行这个,我得到不同的数字作为输出 – 3,3,3,4,6,6和2,2,3,5,5,6等。
我尝试使用锁定对象,但它没有正确执行。 任何人都可以帮我解决这个问题。 我只是想确保每个线程/任务获得正确的索引。 请注意,每个任务都被强制在单独的线程上运行。

 List tasks1 = new List(); for (int j = 1; j  { Console.WriteLine(j); } , new CancellationToken() , TaskCreationOptions.LongRunning , TaskScheduler.Default) ); } Task.WaitAll(tasks1.ToArray()); Console.Read(); 

你正在“捕获循环变量”。 j在lambda中使用的事实意味着编译器将以不同的方式对待它(实质上,它将被装箱)并且所有线程将使用相同的共享变量。

简短修复:

  for (int j = 1; j <= 5; j++) { int jCopy = j; tasks1.Add(Task.Factory.StartNew(() => { Console.WriteLine(jCopy); }, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default) ); } 

只是为了完成其他答案。 在C#5.0(.NET 4.5)中,关闭foreach循环变量有一个重大变化,但是没有关闭for循环变量。

请参阅Eric Lippert的详细信息(和前言更新说明) 。 关闭循环变量被认为是有害的 ,他的Closing over the loop变量,第二部分

请注意,此问题与multithreading或TPL(任务并行库)用法无关。

其他答案和评论提到它之前已经讨论过,但没有链接到任何先前的答案。 以下是一些,为了相互联系:

  • 访问修改后的关闭
  • 获得修改后的封闭(2)
  • C#捕获变量循环
  • ReSharper警告 – 访问修改后的关闭
  • ReSharper中修改了闭包警告
  • 来自Eric Lippert的博客:“不要关闭循环变量”[重复]
  • 为什么在lambda表达式中使用迭代变量是不好的
  • 我如何解决这个lambda表达式外部变量问题?
  • 在WPF按钮上单击事件时使用lambda表达式时出现奇怪的行为
  • C# – foreach标识符和闭包
  • 如何告诉lambda函数在C#中捕获副本而不是引用?
  • 为什么我会得到:“lambda表达式中的迭代变量可能会产生意外结果”[重复]
  • 此代码是否真的导致“访问修改后的闭包”问题?
  • 为什么在lambda表达式中使用迭代变量是不好的
  • 如何抑制VB的“迭代变量不应该在lambda表达式中使用”
  • 在c#中同时运行相同方法的多个实例而不会丢失数据?
  • 闭包对循环变量的正确语义是什么? [关闭]
  • 循环中lambdas的引擎代码生成下的C#
  • 向Linq 2 Sql查询动态添加未确定数量的子句的正确方法是什么?
  • 等等

回答了数百万次。 它与关闭有关。 更改您的代码如下

  for (int j = 1; j <= 5; j++) { int temp = j; tasks1.Add(Task.Factory.StartNew(() => { Console.WriteLine(temp); }, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default) ); } 

我建议你阅读: 循环变量和闭包