c# - Task.WaitAll 抛出 OperationCanceledException

标签 c# multithreading task-parallel-library multitasking

<分区>

我有一个具有相同 CancellationTokenSource 的正在运行的任务列表。

我希望当前线程一直等到所有任务完成直到任务被取消。

Task.WaitAll(tasks.ToArray(), searchCencellationTokenSource.Token);
System.Console.WriteLine("Done !");

即使当前线程处于等待状态,任务也可能被另一个任务取消。这是正常行为。

但是,当当前线程处于等待状态并且另一个任务取消任务时,WaitAll 会抛出 CancellationTokenSource 并显示一条消息:“操作已取消。”。

我知道它被取消了,我是故意的。我只是希望它在任务取消或完成后继续执行下一个代码,而不抛出异常。

我知道我可以用 try & catch 包装这段代码,但抛出异常是繁重的操作,我不希望它发生在像这样的正常行为上。

最佳答案

这种阻塞机制可以改写为:

Task.WhenAll(taskA, taskB, taskC).Wait()

这为您提供了一个我们可以等待但也可以管理取消的任务。因此,要忽略取消异常,您可以执行以下操作:

Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait();

不会抛出 OperationCancelledException

然后可以将其包装到扩展方法中,如下所示:

public static class TaskExtensions
{
    public static Task IgnoreCancellation(this Task task)
    {
        return task.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
    }
}

这将允许您再次编写以下内容而不会遇到 OperationCancelledException:

Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait();

这是一个显示该方法有效的测试夹具:

public class IgnoreTaskCancellation
{
    [Fact]
    public void ShouldThrowAnAggregateException()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);

        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);

        Assert.Throws<AggregateException>(() => Task.WhenAll(taskA, taskB, taskC).Wait());
    }

    [Fact]
    public void ShouldNotThrowAnException()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);

        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);

        Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait();
    }

    [Fact]
    public void ShouldNotThrowAnExceptionUsingIgnore()
    {
        CancellationTokenSource cts = new CancellationTokenSource(10);

        Task taskA = Task.Delay(20, cts.Token);
        Task taskB = Task.Delay(20, cts.Token);
        Task taskC = Task.Delay(20, cts.Token);

        Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait();
    }
}

希望对您有所帮助。

关于c# - Task.WaitAll 抛出 OperationCanceledException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40595720/

相关文章:

C++ 静态类成员指的是自身

c# - 为什么取消父任务时不会触发子任务的任务继续?

c# - C#忽略子字符串错误/警告

c# - "in"通用参数有什么作用?

multithreading - 在混合 MPI/OpenMP 中进行 MPI 调用的线程

java - Java中的最终静态变量是线程安全的吗?

c# - 在任务中捕获异常的最佳方法是什么?

c# - 等待后任务继续不工作

c# - 我如何使用线程在 XNA 中运行数据库查询?

c# - 如何根据控件的大小排列控件? (不继承面板)