为什么Task.WaitAll不等待我的所有任务完成?C#

为什么Task.WaitAll不等待我的所有任务完成?C#,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,在我开始之前。我看过类似的问题,但我认为在我的情况下,这些问题没有答案 我对Task.Factory.StartNew和Task.WaitAll有问题 我在任务中初始化的已创建类中的对象上获得null异常,即使引发null异常的代码应该等待所有任务完成 如果我在没有任务的情况下运行这段代码,它可以正常工作 为什么Task.WaitAll不等待所有任务完成 Queue<Task> tasks = new Queue<Task>(); //Go

在我开始之前。我看过类似的问题,但我认为在我的情况下,这些问题没有答案

我对Task.Factory.StartNew和Task.WaitAll有问题

我在任务中初始化的已创建类中的对象上获得null异常,即使引发null异常的代码应该等待所有任务完成

如果我在没有任务的情况下运行这段代码,它可以正常工作

为什么Task.WaitAll不等待所有任务完成

        Queue<Task> tasks = new Queue<Task>();
        //Go through all transactions in the file via the reader.
        foreach (transaction t in xr.read_x12(_progressbar_all_processing)) {
            tasks.Enqueue(Task.Factory.StartNew(() => {
                //Create a new provider from the current transaction and then
                //add it to the global provider list.
                provider p = new provider(t);

                t_info.provider_list.Add(p);

                //Null out the segments of the current transaction
                //We are done with them and now the garbage collector
                //can clean them up for us.
                t.segments = null;
            }));
        }
        Task.WaitAll(tasks.ToArray());

        foreach(provider p in t_info.providers){
              //Every provider has a List<claims> claims_list
              //Do something with p.claims_list
              foreach(claim c in p.claims_list){ //<--null exception here

              }
        }
Queue tasks=new Queue();
//通过读卡器查看文件中的所有事务。
foreach(xr.read_x12(\u progressbar\u all\u processing)中的事务t){
tasks.Enqueue(Task.Factory.StartNew(()=>{
//从当前事务创建新的提供程序,然后
//将其添加到全局提供程序列表中。
提供商p=新提供商(t);
t_info.provider_list.Add(p);
//清空当前事务的段
//我们已经完成了它们,现在是垃圾收集器
//我可以帮我们清理一下。
t、 段=空;
}));
}
Task.WaitAll(tasks.ToArray());
foreach(t_信息提供者中的提供者p){
//每个提供者都有一个索赔清单
//用p.U清单做点什么

foreach(p.claims_list中的claim c){/
t_info.provider_list
是一个
列表
这个类不能同时让多个线程写入,必须同步对该列表的访问

lock(t_info.provider_list)
{
    t_info.provider_list.Add(p);
}

这将只允许一个线程一次执行Add调用,并将修复集合损坏的问题。

一个更容易纠正的建议:使用
Task。而不是使用
。使每个任务返回一个值,该值是其自身工作单元的结果

当所有
都有签名时:

Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
Task whalll(IEnumerable任务)

因此,您将一组任务传递给它,每个任务的计算结果都是
TResult
,然后返回一个任务,该任务的计算结果是一个数组,其中包含完成后的所有结果

通过这种方式,您可以免除使用线程安全集合在任务之间传递数据的任何责任。出错的可能性要大得多


它还与
async
/
await
兼容,后者都是关于使用通过任务返回的值。

您永远不应该使用
StartNew
(这不是您的问题,但您应该注意)。对于您的实际问题,
t\u info.provider\u list
的类型是什么?@ScottChamberlain-谢谢,我会记住这一点。它是list,provider有一个list。所有这些都是在provider中生成的constructor@Quantic如果任务出现故障
task.WaitAll
将抛出一个
agragateException
谢谢Scott,这似乎是错误的o已经解决了我的问题。以后我会尽量更加小心我的线程。