2012-11-12 164 views
7

我試圖通過調用任務中的CancellationTokenSource.Cancel()方法來取消任務<>,但我無法使其工作。取消任務中的任務

這裏是代碼我使用:

TaskScheduler ts = TaskScheduler.Current; 

CancellationTokenSource cts = new CancellationTokenSource(); 

Task t = new Task(() => 
{ 
    Console.WriteLine("In Task"); 
    cts.Cancel(); 
}, cts.Token); 

Task c1 = t.ContinueWith(antecedent => 
{ 
    Console.WriteLine("In ContinueWith 1"); 
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ts); 

Task c2 = c1.ContinueWith(antecedent => 
{ 
    Console.WriteLine("In ContinueWith 2"); 
}, TaskContinuationOptions.NotOnCanceled); 

t.Start(); 

Console.ReadKey(); 

Environment.Exit(1); 

此打印輸出:

In Task 
In ContinueWith 1 
In ContinueWith 2 

我希望是這樣的:

In Task 

我在這裏失去了一些東西?任務只能取消以外的的任務嗎?

+0

我想,你不明白取消原則。請參閱'CancellationToken.ThrowIfCancellationRequested'方法。 –

+0

那是因爲我只開始學習TPL。 – Intrepid

+0

我覺得這是一個非常好的問題,很驚訝能夠重現。 –

回答

7

任務只考慮「取消」,如果

  • 其取消標記將被取消其開始執行之前。在執行過程中
  • 其取消標記被取消,該代碼通過如果添加了cts.Token.ThrowIfCancellationRequested()線後cts.Cancel()然後事情就表現(通過代碼調用cts.Token.ThrowIfCancellationRequested()通常)

拋OperationCancelledException共同遵守取消如你所料。在你的例子中,取消是在任務運行時發生的,但是任務沒有觀察到取消,並且任務的動作運行完成。所以這個任務被標記爲「跑到完成」。

通過檢查延續中的取消標記(cts.Token.IsCancellationRequested),可以檢查「執行完成」任務的情況,但被取消(在任務完成期間或完成後)。另一個有時候有所幫助的選擇是使用原始的取消標記作爲延續的取消標記(這樣,如果取消未被先行任務發現,它至少會被延續所尊重) - 因爲TPL在它甚至有機會跑之前將會將繼續標記爲已取消。

+0

我會接受你的答案,因爲它是有道理的。我也設法使用您提供的信息按預期工作。 – Intrepid

+0

太好了 - 非常感謝你回報。 –

+0

@MattSmith:你的意思是'原始的取消令牌作爲繼續的取消令牌。..你是否介意通過編輯回答提供代碼片段.. – dotNETbeginner

0

此代碼段按預期工作。

var cts = new CancellationTokenSource(); 

      var t = new Task(() => 
      { 
       Console.WriteLine("In Task"); 
       cts.Cancel(); 
      }, cts.Token); 

      Task c1 = t.ContinueWith(antecedent => 
      { 
       Console.WriteLine("In ContinueWith 1"); 
      }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled/* by definition from MSDN here must be NotOnCanceled*/, TaskScheduler.Current); 

      c1.ContinueWith(antecedent => 
      { 
       Console.WriteLine("In ContinueWith 2"); 
      }, TaskContinuationOptions.NotOnCanceled); 

      t.Start(); 
      Console.ReadKey(); 

      Environment.Exit(1); 

但似乎有TaskContinuationOptions枚舉中的錯誤。

NotOnCanceled指定如果繼續任務的前導被取消,則該繼續任務不應該排定爲 。該選項對於 多任務延續無效。

OnlyOnCanceled指定僅在其先行項被取消時計劃繼續任務應爲 。該選項不是 適用於多任務延續。

+0

如果您註釋掉'cts.Cancel();'行,它不會像我期望的那樣執行第二個ContinueWith()。我期待在ContinueWith 2中顯示。 – Intrepid