2011-08-17 28 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。 –