C# 线程安全和任务。工厂
我对并行编程相当陌生C# 线程安全和任务。工厂,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,我对并行编程相当陌生 我想做一些与任务相关的工作 每个任务都是使用param启动的,以便使用id执行一些简单的工作 但似乎所有的情妇都搞混了 我确信我缺少线程安全的一些关键元素 你能帮我理解我做错了什么吗 我不需要任务的任何返回值,我只需要他们完成他们的工作 static void Main(string[] args) { int NumberOfTasks = 10; Task[] tasks = new Task[NumberOfTasks]; for (int
我想做一些与任务相关的工作
每个任务都是使用param启动的,以便使用id执行一些简单的工作
但似乎所有的情妇都搞混了 我确信我缺少线程安全的一些关键元素
你能帮我理解我做错了什么吗 我不需要任务的任何返回值,我只需要他们完成他们的工作
static void Main(string[] args)
{
int NumberOfTasks = 10;
Task[] tasks = new Task[NumberOfTasks];
for (int i = 0; i < NumberOfTasks; i++)
{
tasks[i] = Task.Factory.StartNew(() => DoSafeWork(i));
}
Task.WaitAll(tasks);
Console.WriteLine("Done !");
Console.ReadKey();
}
private static void DoSafeWork(int i)
{
Console.WriteLine("working on Task {0} ", i.ToString());
}
问题在于循环变量是在循环外部定义的。请注意,问题的根源实际上是闭包,与线程无关 只需像这样创建循环变量的本地副本,以便闭包捕获副本:
for (int i = 0; i < NumberOfTasks; i++)
{
var localCopy = i;
tasks[i] = Task.Factory.StartNew(() => DoSafeWork(localCopy));
}
for(int i=0;iDoSafeWork(localCopy));
}
有关详细说明,请参阅。问题在于,正如DMI所说,您正在关闭索引,因此所有任务都引用相同的索引,而
for
循环会更改它
虽然可以通过将当前索引值复制到局部变量来解决此问题,但更优雅的解决方案是使用LINQ:
var tasks = Enumerable.Range(0, NumberOfTasks).Select(i => Task.Factory.StartNew(() => DoSafeWork(i)));
Task.WaitAll(tasks);
此外,如果您不受.Net旧版本的限制,则应使用Task.Run
、Task.whalll
和wait
:
var tasks = Enumerable.Range(0, NumberOfTasks).Select(i => Task.Run(() => DoSafeWork(i)));
await Task.WhenAll(tasks);
@Euphoric的可能复制它不是,因为
foreach
和for
@l3arnon的行为不同。是的,它在较新的C版本中得到了修复。但问题仍然是一样的。在使用诸如int32@fubo这是一个普遍的假设,但事实并非如此。请参阅Skeet先生本人的深入解释。
var tasks = Enumerable.Range(0, NumberOfTasks).Select(i => Task.Run(() => DoSafeWork(i)));
await Task.WhenAll(tasks);