2014-02-20 101 views
1

下面的代码不能像我期望的那样工作。我究竟做错了什么?每次运行的输出都不相同。有没有更好的方法来做到这一点?假设行动做了比下面更复杂的事情。线程安全传递整数到任务执行任务

Action<int> action = (int m) => 
{ 
    if ((m % 2) == 0) 
     Console.WriteLine("Even"); 
    else 
     Console.WriteLine("Odd"); 
}; 

const int n = 10; 
Task[] tasks = new Task[n]; 
for (int i = 0; i < n; i++) 
{ 
    tasks[i] = Task.Factory.StartNew(() => action(i+1)); 
} 
Task.WaitAll(tasks); 
+2

嗯,为什么这是downvoted?我确信它是重复的,但在我的脑海里,这是一个完全有效的,适当的问题。 – Cameron

+2

@Cameron:Upvoted它,所以它再次0 :-) – sprinter252

+0

我没有downvote,但这个问题已被问了很多次之前。另外,问题的有效性在重复时无关紧要。 – Matthew

回答

3

在循环拉姆达每循环一次,而不是它的价值捕捉一个参照同i变量

你的循环更改为类似:

for (int i = 0; i < n; i++) 
{ 
    var j = i; 
    tasks[i] = Task.Factory.StartNew(() => action(j+1)); 
} 

请注意,输出仍然会在每次运行不同,但你应该正好五个甚至五奇输出。

+1

相关的答案:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – Matthew

+0

谢谢卡梅隆。很好的答案。并感谢链接。 – Tigran

+1

想到我也会展示这个http://stackoverflow.com/questions/14907987/access-to-foreach-variable-inclosure。值得注意的是,您在此处看到的行为在编译器版本上会有所不同。在.NET 4.5中,你不会有这个问题,因为它们改变了关闭的工作方式 – devshorts