Task.WaitAll和Exceptions

thu*_*eys 28 .net c# parallel-processing

我有异常处理和并行任务的问题.

下面显示的代码启动2个任务并等待它们完成.我的问题是,如果任务抛出异常,则永远不会到达catch处理程序.

        List<Task> tasks = new List<Task>();
        try
        {                
            tasks.Add(Task.Factory.StartNew(TaskMethod1));
            tasks.Add(Task.Factory.StartNew(TaskMethod2));

            var arr = tasks.ToArray();                
            Task.WaitAll(arr);
        }
        catch (AggregateException e)
        {
            // do something
        }
Run Code Online (Sandbox Code Playgroud)

但是,当我使用以下代码等待超时的任务时,会捕获异常.

 while(!Task.WaitAll(arr,100));
Run Code Online (Sandbox Code Playgroud)

我似乎错过了一些东西,因为文档WaitAll描述了我的第一次尝试是正确的.请帮助我理解它为什么不起作用.

Jon*_*eet 26

无法重现这一点 - 它适用于我:

using System;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000));
        Task t2 = Task.Factory.StartNew(() => {
            Thread.Sleep(500);
            throw new Exception("Oops");
        });

        try
        {
            Task.WaitAll(t1, t2);
            Console.WriteLine("All done");
        }
        catch (AggregateException)
        {
            Console.WriteLine("Something went wrong");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

就像我期望的那样,打印出"出了问题".

您的某个任务可能没有完成吗?WaitAll确实等待所有任务完成,即使有些任务已经失败.

  • @pivotnig - 在这里看一下'Creating Task Continuations'来明确表达依赖关系 - http://msdn.microsoft.com/en-us/library/dd537609.aspx (6认同)
  • 谢谢你快速回答乔恩!我的问题是,其他任务取决于失败的任务,因此它将永远等待失败的任务.我的想法是,当任务失败时会立即捕获异常,但事实并非如此.感谢您指出了这一点. (2认同)

gap*_*gap 11

以下是我解决问题的方法,正如我在回答/问题的评论中提到的那样(上图):

调用者捕获由屏障协调的任务引发的任何异常,并通过强制取消发出其他任务的信号:

CancellationTokenSource cancelSignal = new CancellationTokenSource();
try
{
    // do work
    List<Task> workerTasks = new List<Task>();
    foreach (Worker w in someArray)
    {
        workerTasks.Add(w.DoAsyncWork(cancelSignal.Token);
    }
    while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ;

 }
 catch (Exception)
 {
     cancelSignal.Cancel();
     throw;
 }
Run Code Online (Sandbox Code Playgroud)

  • 这很好.从未实现过"CancellationTokenSource"的这个用例. (2认同)