【问题标题】:C# Task.WaitAll() Cancelation with Error handlingC# Task.WaitAll() 取消错误处理
【发布时间】:2017-04-16 04:37:09
【问题描述】:

我有问题。 我尝试运行多个长时间运行的任务。如果一个失败,我想取消所有其他任务并获得失败异常。 下面给出的例子。 我想用

抛出的异常捕获 AggregateException
 throw new Exception("FailureTask");

但我捕获的是 OperationCanceledException 而不是 AggregateException,因为我想取消所有其他任务。

    [TestMethod]
    public void TestParallelTaskCancelation()
    {
        var cancellationTokenSource = new CancellationTokenSource();
        Task[] tasks =
        {
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
            Task.Factory.StartNew(FailureTask, cancellationTokenSource, cancellationTokenSource.Token)
        };

        try
        {
            Task.WaitAll(tasks, cancellationTokenSource.Token);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.GetaAllMessages());
        }
        catch (AggregateException e)
        {
            Console.WriteLine(e.GetaAllMessages());
        }
    }

    private void DummyTask(object o)
    {
        var cancellationToken = (CancellationTokenSource)o;
        while (true)
        {
            Thread.Sleep(10000);
            if (cancellationToken.IsCancellationRequested)
            {
                cancellationToken.Token.ThrowIfCancellationRequested();
            }
        }
    }

    private void FailureTask(object o)
    {
        var cancellationToken = (CancellationTokenSource)o;

        var executionTask = Task.Factory.StartNew(() =>
        {
            Thread.Sleep(1000);
            throw new Exception("FailureTask");
        }, cancellationToken.Token);

        executionTask.ContinueWith(t =>
        {
            cancellationToken.Cancel(false);
            throw new Exception(t.Exception.GetaAllMessages());
        }, TaskContinuationOptions.OnlyOnFaulted);

        if (executionTask.Wait(10 * 1000, cancellationToken.Token)) return;
        //timeout !!!
        throw new Exception("The limit 'Max Seconds Per Query' has been exceeded!!!");
    }`

请帮忙。

【问题讨论】:

  • 你抛出一个Exception,它是所有异常的基类。 OperationCanceledExceptionAggregateException 派生自 Exception。您的异常永远不会被捕获,因为您只是捕获更具体的异常。要捕获AggregateException,您必须抛出AggregateException
  • 如果两个或多个任务同时失败怎么办。那么我将捕获哪个异常?据我了解,AggregateException 应该包括取消任务的取消异常和其他任务的异常。
  • 抛出 throw new AggregateException("FailureTask");没用。即使只捕获(基本)异常也会捕获 OperationCanceledException。
  • @ThomasSchneiter 这不是 100% 正确的。 Taks.WaitAll 将触发“OperationCanceledException”,因为它是取消。如果您取消任务,则会抛出 AggregateException。

标签: c# exception-handling synchronization task aggregateexception


【解决方案1】:

这对我有用

public static async void TestParallelTaskCancelation()
    {
        var cancellationTokenSource = new CancellationTokenSource();
        Task[] tasks =
        {
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(DummyTask, cancellationTokenSource, cancellationTokenSource.Token),
        Task.Factory.StartNew(FailureTask, cancellationTokenSource, cancellationTokenSource.Token)
        };

        try
        {
           await Task.WhenAll(tasks);
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.ToString());
        }
        catch (AggregateException e)
        {
            Console.WriteLine(e.ToString());
        }
    }

【讨论】:

  • 这是正确的答案 :-) 你比我快...,你不必取消等待,因为你想等到所有其他线程都被取消
  • 不,如果一个失败,我需要取消所有其他。
  • FailureTask 失败时,所有其他的都会用cancellationToken 取消
  • 会通过cancellationTokenSource被取消。使用 Task.WaitAll(tasks, cancellationTokenSource.Token) 您只需取消等待,而不是您之前创建的任务。
  • 这成功了。问题是为什么。删除 cancellationTokenSource.Token 表单 Task.WaitAll()
【解决方案2】:

您应该使用 for throw AggregateException 构造函数,而不仅仅是 Exception

throw new AggregateException ("FailureTask");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-04
    • 2016-07-11
    • 2017-01-09
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    相关资源
    最近更新 更多