2011-08-17 72 views
3

考慮下面的C#代碼:爲什麼在取消父項時未觸發子任務的任務延續?

CancellationTokenSource tCancelSource = new CancellationTokenSource(); 
var tTask = Task.Factory.StartNew 
(
    () => 
    { 
// Start child 
     Task.Factory.StartNew 
     (() => 
      { 
       Thread.Sleep(2000); 
       Console.WriteLine("A"); 
       tCancelSource.Token.ThrowIfCancellationRequested(); 
      } 
     , tCancelSource.Token 
     , TaskCreationOptions.AttachedToParent 
     , TaskScheduler.Current 
     ) 
     .ContinueWith 
      (
      t => 
       { 
        Console.WriteLine("B"); 
       } 
      , tCancelSource.Token, TaskContinuationOptions.AttachedToParent 
      , TaskScheduler.Current 
     ); 
    } 
    , tCancelSource.Token, TaskCreationOptions.PreferFairness 
    , TaskScheduler.Current 
) 
.ContinueWith 
     (t => Console.WriteLine("C")); 
Thread.Sleep(500); 
tCancelSource.Cancel(); 
tTask.Wait(); 
Console.WriteLine("Done"); Console.Read(); 

子任務的延續不會觸發,即B沒有打印到控制檯。註釋掉調用取消將打印B.

觀察:

A 
C 

預計

A 
B 
C 

看來,如果家長被取消子任務的繼續不解僱,但我無法找到這個記錄。任何人都知道爲什麼/這裏發生了什麼,或者這將記錄在哪裏?

編輯:

我忘了將取消標記傳遞給最後的延續。事實上,我發現文檔內容如下: 「[...]如果先行者被取消,繼續將不會開始」,但是我被選項TaskContinuation.OnlyOnCanceled弄糊塗了。這種情況是可能的,例如

CancellationTokenSource tSource = new CancellationTokenSource(); 
Task tTest = Task.Factory.StartNew 
     (
      () => 
      { 
       throw new Exception("foobar"); 
      }, tSource.Token).ContinueWith(t => 
       { 
        Console.WriteLine("A " + t.Status); 
        } 
      , tSource.Token 
      , TaskContinuationOptions.NotOnFaulted 
      , TaskScheduler.Current 
     ) 
      .ContinueWith 
       (
       t => 
        { 
         Console.WriteLine("B " + t.Status); 
        } 
       , tSource.Token 
       ); 

tTest.Wait(); 
Console.Read(); 

第一延續設置爲取消狀態(如它的TaskContinuationOptions值使其不運行),而令牌被設置爲取消。所以最後的延續在這裏運行。

回答

1

現在我知道了。您的任務和嵌套任務中的代表立即開始。嵌套任務開始等待2000毫秒,但它已經超出了檢查取消令牌的程度。嵌套任務中的2000 ms等待會導致繼續取消,因爲同時取消令牌被取消。但是,父任務的繼續沒有取消令牌,因此它始終運行。

編輯:問題是兩個任務使用相同的取消標記。

+0

我在文檔中錯過了「[...]如果先行者被取消了,繼續將不會開始。」我有點困惑的選項TaskContinuationOptions.OnlyOnCanceled,我似乎無法想象的情況下,前提取消,使延續運行(先前在取消狀態)。 – Marcus

+0

你是指功能?從技術上講,你幾乎是自己創建了一個場景如果您在創建標記後立即取消該標記,請查看會發生什麼。 –

3

最終,如果子任務連接到它的父級,那麼它依賴於它,並且由於您使用的是相同的取消標記,因此您可以預期此行爲。您可以使用單獨的取消令牌,但是我認爲您需要處理冒泡取消異常以保持流量 - 另一種選擇是分離任務。

您可能需要檢查herehere以瞭解取消文件。

+4

t你可以twant tto tavoid thaving tyour tcat twalk tover tyour tkeyboard twhen tyou tpost tanswers。 –