【问题标题】:Why is Task.IsCanceled Not True?为什么 Task.IsCanceled 不正确?
【发布时间】:2013-12-26 09:10:53
【问题描述】:

我这里有一个简单的程序

private static void CancellingSingleTask()
{
    DateTime whenStarted = DateTime.Now;

    Console.WriteLine("[{0}] - Main: Started", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));

    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken ct = cts.Token;

    Task task = Task.Factory.StartNew(() => 
    {
        int? taskId = Task.CurrentId;

        Console.WriteLine("[{0}] - Task - [{1}]:  Started", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks), taskId);

        Thread.Sleep(2000);

        if (ct.IsCancellationRequested)
        {
            Console.WriteLine("[{0}] - Task - [{1}]:  Cancellation Requested", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks), taskId);
            throw new OperationCanceledException();
        }
        Console.WriteLine("[{0}] - Task - [{1}]:  No Cancellation Requested", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks), taskId);
    }, ct);

    Action Print = () =>
    {
        Console.WriteLine("[{0}] - Main: Task.IsCanceled = [{1}]  Task.IsFaulted = [{2}] Task.IsCompleted = [{3}] Task.Status = [{4}]", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks),
            task.IsCanceled, task.IsFaulted, task.IsCompleted, task.Status);
    };

    Console.WriteLine("[{0}] - Main: Started New Task", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));
    Print();

    Thread.Sleep(1000);

    Console.WriteLine("[{0}] - Main: Cancelling Task", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));

    cts.Cancel();

    Thread.Sleep(2000);

    Console.WriteLine("[{0}] - Main: After Cancelling Task", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));
    Print();

    try
    {
        Console.WriteLine("[{0}] - Main: Waiting For Task", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));

        task.Wait();

        Console.WriteLine("[{0}] - Main: After Waiting For Task", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));
        Print();
    }
    catch (AggregateException aggregateException)
    {
        Thread.Sleep(2000);
        Console.WriteLine("[{0}] - Main: In Catch Block", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks));
        Print();

        foreach (var exception in aggregateException.InnerExceptions)
        {
            Console.WriteLine("[{0}] - Main: Received Exception In Task [{1}]", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks), exception.Message);
        }
    }

} 

样本输出
[00:00:00.0010000] - 主要:开始
[00:00:00.0040002] - 主要:开始新任务
[00:00:00.0060003] - 主要:IsCanceled = [False] IsFaulted = [False] IsCompleted = [False] 状态 = [Running]
[00:00:00.0070004] - 任务 - [1]:已开始
[00:00:01.0070576] - 主要:取消任务
[00:00:02.0071148] - 任务 - [1]:请求取消
[00:00:03.0111722] - 主要:取消任务后
[00:00:03.0111722] - 主要:IsCanceled = [False] IsFaulted = [True] IsCompleted = [True] 状态 = [Faulted]
[00:00:03.0111722] - 主要:等待任务
[00:00:05.0112866] - 主要:在 Catch 块中
[00:00:05.0112866] - 主要:IsCanceled = [False] IsFaulted = [True] IsCompleted = [True] 状态 = [Faulted]
[00:00:05.0112866] - 主要:在任务中收到异常 [操作已取消。]

我从来没有看到 Task.IsCanceled 设置为 true,我是在犯错还是遗漏了一些明显的东西。 我已经对此问题进行了一些研究/搜索,但无法找到确凿的答案。

注意:StackOverFlow 上的相关问题 Cancellation of a tasktask IsCanceled is false, while I canceledTask.IsCancelled doesn't work

【问题讨论】:

  • throw new OperationCanceledException(ct);?或ct.ThrowIfCancellationRequested() ?

标签: c# .net task-parallel-library


【解决方案1】:

我想你应该将CancellationToken 传递给OperationCanceledException 的构造函数。

  if (ct.IsCancellationRequested)
    {
        Console.WriteLine("[{0}] - Task - [{1}]:  Cancellation Requested", TimeSpan.FromTicks(DateTime.Now.Ticks - whenStarted.Ticks), taskId);
        throw new OperationCanceledException(ct);
    }

TPL 将检查两个CancellationToken 是否相同,如果是,它将把任务标记为Cancelled,在你的情况下它不是,所以 TPL 假设你的任务没有被取消。

或者更好的使用ThrowIfCancellationRequested方法,就这么简单

ct.ThrowIfCancellationRequested();

【讨论】:

  • 所以这是一个双向过程,在CancellationTokenSource.Cancel 之后,任务应该通过CancellationToken 明确确认取消,抛出OperationCanceledException 是不够的。这清除了很多东西。谢谢。
  • 当然可以,这就是为什么微软将这种模式称为合作取消。检查this,阅读解释这件事的前两个要点:)
猜你喜欢
  • 2011-08-18
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 2011-11-12
  • 2018-06-24
  • 2014-03-20
相关资源
最近更新 更多