Closed. This question needs to be more focused。它当前不接受答案。












想要改善这个问题吗?更新问题,使它仅关注editing this post的一个问题。

4年前关闭。



Improve this question




我有一个具有相同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/

10-10 18:42