在我开始之前。我看过类似的问题,但我认为他们没有答案。
我遇到Task.Factory.StartNew和Task.WaitAll的问题。
我在任务中初始化的已创建类中的对象上获得null异常,即使抛出空异常的代码应该等待所有任务完成。
如果我在没有任务的情况下运行此代码,它可以正常工作。
为什么Task.Wait会等到所有任务都完成后才等待?
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
}
}
答案 0 :(得分:1)
t_info.provider_list
是List<provider>
这个类一次有多个线程写入它是不安全的,你必须同步访问列表。
lock(t_info.provider_list)
{
t_info.provider_list.Add(p);
}
这样只允许一个线程一次执行Add调用,并将修复您的问题。
答案 1 :(得分:1)
建议您更容易做到:使用"li"
代替。使每个任务返回一个值,该值是其自身工作单元的结果。
Task.WhenAll
有签名:
WhenAll
因此,您将每个评估为Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
的任务集合传递给它,然后您将返回一个任务,该任务在完成后会计算出包含所有结果的数组。
这样,您就免除了使用线程安全集合在任务之间传递数据的任何责任。错误要困难得多。
它还与TResult
/ async
兼容,这与消耗通过任务返回的值有关。