2017-02-21 4 views
1

취소 토큰을 수락하는 복수의 작업이 있으므로 그에 따라 ThrowIfCancellationRequested을 호출하십시오. 이러한 작업은 Task.WhenAll을 사용하여 동시에 실행됩니다. 어떤 작업에서 예외가 발생하면 모든 작업을 취소하고 싶습니다.제대로 Task.WhenAll을 취소하고 첫 번째 예외를 던져?

var cts = new CancellationTokenSource(); 

try 
{ 
    var tasks = new Task[] { DoSomethingAsync(cts.Token), ... } // multiple tasks here 
     .Select(task => task.ContinueWith(task => 
     { 
      if (task.IsFaulted) 
      { 
       cts.Cancel(); 
      } 
     })); 

    await Task.WhenAll(tasks).ConfigureAwait(false); 
} 
catch (SpecificException) 
{ 
    // Why is this block never reached? 
} 

I는이 작업을 수행하는 가장 좋은 방법입니다 있는지 확실하지 않습니다, 몇 가지 문제를 갖고있는 것 같아요 :이 SelectContinueWith을 사용하여 달성. 예외는 내부적으로 catch되며, WhenAll 이후의 코드는 항상 발생합니다. 예외가 발생했을 때 WhenAll에 도달 한 후 코드를 원하지 않습니다. 예외가 발생하여 호출 스택의 다른 레벨에서 수동으로 catch 할 수 있습니다. 이것을 달성하는 가장 좋은 방법은 무엇입니까? 가능한 경우 호출 스택을 그대로 유지하고 싶습니다. 복수의 예외가 발생했을 경우는, 최초의 예외 만이 다시 슬로우되면 (자), AggregateException가 아닌 것이 최적입니다. task.ContinueWith(lambda, cts.Token) : 관련 메모에


, 정말 같은 ContinueWith에 취소 토큰을 전달했습니다. 그러나, 어떤 작업에서 예외가 발생하면, 결국 TaskCanceledException을 던져 버릴 것입니다. 취소 토큰을 ContinueWith에 전달해야한다고 생각했는데, 이는 취소 할 것이기 때문에 ContinueWith 그 자체라고 생각하지 않습니다. 내가 원하는거야.

+0

이 Task.WhenAll '에 관한 것입니다 '및 작업 외부에서 try-catch를 사용합니다. 다른 질문은 여러 개의'ContinueWith'에 합류하고 task.Exception을 명시 적으로 점검하는 것입니다. –

+1

차이점은 관련이 없습니다. 'WhenAll'은'ContinueWIth'를 사용하여 자체 연속을 첨부 할 것이며,'Exception' 값을 검사 할 때 자체적으로 오류가 발생할지 여부를 결정할 때 똑같은 문제를 남기게됩니다. 'WhenAll'의 배경에서 문제의 일부를 설명하거나 수정하는 것과 의미있는 차이가없는 것은 아닙니다. – Servy

+0

@Servy 나는 당신의 설명이나 다른 스레드가 호출 스택의 다른 레벨에서 TPL 외부의 예외를 처리 할 수 ​​있도록 예외를 던져 버리는 방법에 대한 내 질문에 대한 답을 이해하지 못합니다. –

답변

5

ContinueWith을 사용하지 않아야합니다. 정답은 각 작업에 계속 부착하는 대신 또 다른 "높은 수준"async 방법을 소개하는 것입니다 :이 질문하고 "복제"의 차이 @Servy

private async Task DoSomethingWithCancel(CancellationTokenSource cts) 
{ 
    try 
    { 
    await DoSomethingAsync(cts.Token).ConfigureAwait(false); 
    } 
    catch 
    { 
    cts.Cancel(); 
    throw; 
    } 
} 


var cts = new CancellationTokenSource(); 
try 
{ 
    var tasks = new Task[] { DoSomethingWithCancel(cts), ... }; 
    await Task.WhenAll(tasks).ConfigureAwait(false); 
} 
catch (SpecificException) 
{ 
    ... 
} 
+2

이것은 훌륭한 해결책 인 것 같습니다. 왜 이것이 다운 보트를 얻었는지 어떤 생각? –

관련 문제