How to cancel and raise an exception on Task.WhenAll if any exception is raised?

懵懂的女人 提交于 2019-12-18 05:12:43

问题


I am waiting on multiples task using Task.WhenAll. When one of them generates an exception I would like Task.WhenAll (or any other way of awaiting multiples tasks) to immediately cancel the others tasks and raise an exception.

Is it possible?

Thanks in advance


回答1:


Cancellation is coopertive the WhenAll can't cancel the threads but you can pass all of them a CancellationToken and fire the token when you get a exception.

CancellationTokenSource cts = new CancellationTokenSource();

var task1 = Func1Async(cts.Token);
task1.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
var task2 = Func2Async(cts.Token);
task2.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
var task3 = Func3Async(cts.Token);
task3.ContinueWith(task => cts.Cancel(), cts.Token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);

await Task.WhenAll(task1, task2, task3);

from inside the methods you will need to put token.ThrowIfCancellationRequested() inside the functions to check the token and cancel the task

public async Task Func1Async(CancellationToken token)
{
    foreach(var item in GetItems1())
    {
         await item.ProcessAsync(token);
         token.ThrowIfCancellationRequested();
    }
}

NOTE: You could clean up the code a bit by making a extension method

public static class ExtensionMethods
{
    public Task CancelOnFaulted(this Task task, CancellationTokenSource cts)
    {
        task.ContinueWith(task => cts.Cancel(), cts.Token, taskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
        return task;
    }

    public Task<T> CancelOnFaulted<T>(this Task<T> task, CancellationTokenSource cts)
    {
        task.ContinueWith(task => cts.Cancel(), cts.Token, taskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
        return task;
    }
}

This would make the code look like

CancellationTokenSource cts = new CancellationTokenSource();

var task1 = Func1Async(cts.Token).CancelOnFaulted(cts);
var task2 = Func2Async(cts.Token).CancelOnFaulted(cts);
var task3 = Func3Async(cts.Token).CancelOnFaulted(cts);

await Task.WhenAll(task1, task2, task3);


来源:https://stackoverflow.com/questions/41899842/how-to-cancel-and-raise-an-exception-on-task-whenall-if-any-exception-is-raised

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!