2017-01-27 102 views
1

我在使用Task.WhenAll等待多重任务。当他们中的一个产生异常时,我想让Task.WhenAll(或等待多个任务的任何其他方式)立即取消其他任务并引发异常。如何取消并在Task.WhenAll引发异常时引发异常?

可能吗?

在此先感谢

+0

你能检查答案吗? http://stackoverflow.com/questions/27238232/how-can-i-cancel-task-whenall –

+2

这不是WhenAll工作的方式。你可能需要重新考虑你的方法。 –

+0

@EvertonSantos感谢您的链接!但我的情况不同,我需要注意异常情况。如果任务中出现异常,我需要取消所有任务 –

回答

7

Cancellation is coopertiveWhenAll无法取消线程,但你可以通过所有他们CancellationToken和火令牌当你得到一个例外。

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); 

从方法里面,你会需要把token.ThrowIfCancellationRequested()的功能里面,以检查令牌和取消任务

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

注意:您可以通过使清理代码位扩展方法

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; 
    } 
} 

这会使代码看起来像

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); 
+0

OP询问'WhenAll'而不是'WaitAll'。 –

+0

@DavidPine这是第一句话中的拼写错误,如果你看看它使用WhenAll的代码示例。 –

+0

我尽可能多地假设,不想编辑你的答案,但不知道这是否是有意的。 –