2017-01-27 7 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

ОП спросил о 'WhenAll' не' WaitAll'. –

+0

@DavidPine Это была опечатка в первом предложении, если вы посмотрите на пример кода, который использует WhenAll там. –

+0

Я так много думал, не хотел редактировать ваш ответ, не зная, было ли это намеренно. –

Смежные вопросы