取消任务中的任务

Int*_*pid 8 c# task task-parallel-library

我试图通过调用任务中的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 );
Run Code Online (Sandbox Code Playgroud)

打印输出:

In Task
In ContinueWith 1
In ContinueWith 2
Run Code Online (Sandbox Code Playgroud)

我的期望是这样的:

In Task
Run Code Online (Sandbox Code Playgroud)

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

Mat*_*ith 8

如果,任务仅被视为"已取消"

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

如果您cts.Token.ThrowIfCancellationRequested()cts.Cancel()事物之后添加了一行,那么事情将按预期运行.在您的示例中,取消发生在任务运行时,但任务不会观察到取消,并且任务的操作将运行完成.因此任务标记为"完成到完成".

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

  • 我只想强调此处“取消”的标准,因为我发现MSDN官方文档存在误导。这意味着任务可以通过抛出“ OperationCanceledException”来取消自身。但这仅在响应取消请求时有效。即使您传递取消令牌,除非您先前已调用`CancellationTokenSource.Cancel()`,否则它将仍被视为常规异常-任务将进入“ IsFaulted”状态,而不是“ IsCanceled”状态。 (2认同)
  • @MattSmith正是我阅读文档时所想到的,但这不是我所看到的。你测试过了吗?这是我的测试:http://pastebin.com/U7LcNvk0我得到的输出是“故障”。如果我取消对“ cts.Cancel”的评论,则会被“取消”。 (2认同)