我正在尝试取消任务<>通过在任务中调用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 :(得分:7)
如果
,任务仅被视为“已取消”cts.Token.ThrowIfCancellationRequested()
的代码)协同观察取消,如果您在cts.Token.ThrowIfCancellationRequested()
之后添加了cts.Cancel()
行,那么事情的行为就像您期望的那样。在您的示例中,取消发生在任务运行时,但任务不会观察到取消,并且任务的操作将运行完成。因此任务标记为“完成任务”。
您可以通过检查延续(cts.Token.IsCancellationRequested
)内的取消令牌来检查“完成任务”但已取消(在任务完成期间或之后)的任务的情况。有时帮助的另一个选项是使用原始取消令牌作为延续的取消令牌(这样,如果先前任务没有注意到取消,它至少会被延续所尊重) - 因为TPL将继续作为取消标记,甚至有机会运行。
答案 1 :(得分: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指定延续任务应该是 只有在其前身被取消时才安排。此选项不是 对多任务延续有效。