10

我试图通过在任务中调用 CancellationTokenSource.Cancel() 方法来取消 Task<>,但我无法让它工作。

这是我正在使用的代码:

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

我在这里错过了什么吗?只能在任务之外取消任务吗?

4

2 回答 2

10

仅在以下情况下才将任务视为“已取消”

  • 它的取消令牌在开始执行之前被取消。
  • 它的取消令牌在执行时被取消,代码通过抛出 OperationCancelledException(通常通过代码调用cts.Token.ThrowIfCancellationRequested())共同观察取消

如果您在 thencts.Token.ThrowIfCancellationRequested()之后添加一行,cts.Cancel()那么事情将按照您的预期进行。在您的示例中,取消发生在任务运行时,但任务没有观察到取消,并且任务的操作运行完成。因此,该任务被标记为“Ran to Completion”。

您可以通过检查延续 ( cts.Token.IsCancellationRequested) 中的取消标记来检查“运行到完成”但被取消(在任务完成期间或之后)的任务情况。有时会有所帮助的另一个选项是使用原始取消令牌作为延续的取消令牌(这样,如果先前的任务没有注意到取消,它至少会受到延续的尊重)——因为 TPL将在它有机会运行之前将延续标记为已取消。

于 2012-11-12T14:52:45.910 回答
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 指定仅当其前件被取消时才应安排继续任务。此选项对多任务延续无效。

于 2012-11-12T13:53:29.883 回答