任务未按预期取消

时间:2015-07-10 15:17:10

标签: c# task cancellation-token

我们得到以下情况:

class Program
{
    static void Main(string[] args)
    {
        // trigger the delayed function
        trigger();

        // cancel the running task.
        _token.Cancel();

        // keep window open ;-)
        Console.ReadLine();

    }

    private static CancellationTokenSource _token = null;
    private static async void trigger()
    {
        _token = new CancellationTokenSource();

        try
        {
            // run task
            await Task.Run(async () =>
            {
                // wait time
                await Task.Delay(2500);

                // we should be cancelled here !!
                Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
                Console.WriteLine("SHOULD NOT HAPPEN");

            }, _token.Token);
        }
        catch (TaskCanceledException)
        {
        }
    }
}

IMO预期的行为是,在处理 Task.Delay(2500)之后,任务的操作主要被取消。

但控制台正在打印:

IsCancellationRequested=True
SHOULD NOT HAPPEN

这只是一个错误。如果将 CancellationToken 作为参数添加到 Task.Delay -Function,它将按预期工作。

那么如果任务中的函数使用 Task.Delay ,你可能不知道如何处理取消?

2 个答案:

答案 0 :(得分:3)

.Net中的取消是合作的。将令牌作为参数传递给Task.Run只会将令牌与返回的任务相关联。

要实际取消任务,您需要检查任务本身内的令牌。如果您希望在延迟内部取消任务,则需要将令牌传递给Task.Delay方法。否则,您只能在延迟之前或之后检查:

await Task.Run(async () =>
{
    _token.Token.ThrowIfCancelltionRequested();
    await Task.Delay(2500, _token.Token);
    _token.Token.ThrowIfCancelltionRequested();

    Console.WriteLine(string.Format("IsCancellationRequested={0}", _token.Token.IsCancellationRequested));
    Console.WriteLine("SHOULD NOT HAPPEN");

}, _token.Token);

答案 1 :(得分:1)

这是一篇很好的MSDN文章:https://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx

  

调用线程不强制结束任务;它只发出信号   请求取消。如果任务已经在运行,那就是   由用户委托来通知请求并做出响应   适当。如果在任务运行之前请求取消,那么   永远不会执行用户委托,并且任务对象会转换   进入已取消状态。

正如i3arnon建议你可以在执行实际工作之前检查状态并抛出异常。代码摘自文章:

...
  // Was cancellation already requested?  
      if (ct.IsCancellationRequested == true) {
         Console.WriteLine("Task {0} was cancelled before it got started.",
                           taskNum);
         ct.ThrowIfCancellationRequested();
      } 
...