Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 线程安全和任务。工厂_C#_Multithreading_Task Parallel Library - Fatal编程技术网

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);