【问题标题】:Throw an aggregate exception from a task won't break all other tasks从任务中引发聚合异常不会破坏所有其他任务
【发布时间】:2013-10-14 21:55:33
【问题描述】:

我有两个任务:

try
{
    List<Task> tasks = new List<Task>();

    Task task1 = Task.Factory.StartNew(() => func(param));
    tasks.Add(task1);
    if (someCondition)
    {
        Task task2 = Task.Factory.StartNew(() => func2(param2));
        tasks.Add(task2);
     }

     tasksArr = tasks.ToArray();

     Task.WaitAll(tasksArr);
 }
 catch (AggregateException e)
 {
     //handle
 }
 catch (Exception)
 {
     //handle
 }

如果其中一个任务发生异常,我将抛出一个新的聚合异常,但只有在第二个任务完成后才到达 catch 语句。我想立即抓住它,以免在第二个任务中进行不必要的工作。

我尝试使用取消令牌:

CancellationTokenSource cts = new CancellationTokenSource();

Task.WaitAll(tasksArr,cts.Token);

但这不是一个好的解决方案,因为它需要处理内部异常 + 捕获的异常将是 OperationCanceledException

有什么想法吗?

【问题讨论】:

  • 似乎func(param)func2(param2) 本身不支持取消,因为CancellationToken 的实例未作为Task 及其委托(方法)的参数传递(请参阅How to: Listen for Cancellation Requests by Polling )。没有CancellationToken,他们怎么能被阻止?如果其中一项任务失败,也许您想取消等待
  • 我想到达 catch 语句,我想取消等待可能是一个解决方案,因为目前我正在完成所有任务后到达 catch 语句。如果其中一项任务失败,我如何取消等待? cts.cancel 将取消所有任务,但 innerexception 会丢失

标签: c# task


【解决方案1】:

要取消等待,必须将CancellationTokenSource 类的实例传递给Task.WaitAll Method (Task[], CancellationToken)。此外,在任务失败(故障,即TaskStatus.Faulted)时运行的每个任务上使用延续

var cancellationTokenSource = new CancellationTokenSource();

var tasks = new List<Task>();

var firstTask = new Task(FirstMethod);
firstTask.ContinueWith(t =>
    {
        Console.WriteLine("First task exception: {0}", t.Exception);
        cancellationTokenSource.Cancel();
    }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
tasks.Add(firstTask);
firstTask.Start();

var secondTask = new Task(SecondMethod);
secondTask.ContinueWith(t =>
    {
        Console.WriteLine("Second task exception: {0}", t.Exception);
        cancellationTokenSource.Cancel();
    }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
tasks.Add(secondTask);
secondTask.Start();

try
{
    var cancellationToken = cancellationTokenSource.Token;
    var tasksArray = tasks.ToArray();
    Task.WaitAll(tasksArray, cancellationToken);
}
catch (Exception e)
{
    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 2019-12-30
    相关资源
    最近更新 更多