2017-03-21 97 views
3

我已經習慣了能夠處理異步操作的取消時,執行一個異步模式:什麼情況下會等待取消的任務拋出TaskCanceledException?

public async Task InvokeAsync(CancellationToken cancellationToken) 
{ 
    using(cancellationToken.Register(handler.Stop)) 
    { 
     try 
     { 
      await handler.HandleAsync(); 
     } 
     catch(HandlerStoppedException ex) 
     { 
      cancellationToken.ThrowIfCancellationRequested(); 
      throw; 
     } 
    } 
} 

的方法調用,其暴露某種取消機構的異步組件。當令牌信號取消請求時,取消令牌設置回調以調用取消機制。

我可以在我的測試中調用此方法以在超時內執行其功能。

async Task TestInvoke() 
{ 
    using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)) 
    { 
     try 
     { 
      await InvokeAsync(timeout.Token); 
     } 
     catch (TaskCancelledException ex) 
     { 
      if (ex.CancellationToken == timeout.Token) 
      { 
       throw new TimeoutException(
        "Operation failed to complete in the allowed time.", ex); 
      } 

      throw; 
     } 
    } 
} 

我的期望是,一個async方法中拋出OperationCanceledException將導致該方法返回過渡到「已取消」狀態Task。然後我期待任何等待這個取消的任務的嘗試應該拋出一個TaskCanceledException

在我目前的情況下(代碼非常類似於上面),當我等待任務時,我得到一個OperationCanceledException。如果我檢查任務的狀態,我可以看到它處於「已取消」狀態,並且沒有與之關聯的異常。

更奇怪的是,如果我在任務上調用Wait(),則會拋出包含預期的TaskCanceledExceptionAggregateException

在什麼情況下等待取消的任務會拋出OperationCanceledException而不是更典型的TaskCanceledException

+0

http://stackoverflow.com/questions/26577519/why-is-taskcanceledexception-thrown-and-does-not-always-breaks-into-the-debugger這應該對你有幫助。 – MetaColon

回答

4

在什麼情況下等待取消的任務會拋棄OperationCanceledException而不是更典型的TaskCanceledException

這個問題太廣泛了。即使人們列舉了今天發生的所有情況,它明天可能會改變。

相反,我會這樣說:

  • TaskCanceledException不是 「更典型」。它最初用於基於動態任務的並行機制,與異步編程無關。
  • OperationCanceledExceptionTaskCanceledException的基類。在你的代碼中,你永遠不應該趕上TaskCanceledException(除非你的做動態任務爲基礎的並行需要訪問TaskCanceledException.Task)。

只是趕上OperationCanceledException而不是。

+0

'TaskCanceledException'由取消任務生成,沒有其他異常在Wait()調用時拋出,並且是由TaskCompletionSource提供的;不管來源如何,它都與基於任務的異步編程密切相關。 –

相關問題