为什么Task.IsCanceled不正确?

1 .net c# task-parallel-library

我这里有一个简单的程序

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);
        }
    }

} 
Run Code Online (Sandbox Code Playgroud)

示例输出
[00:00:00.0010000] - 主要:已启动
[00:00:00.0040002] - 主要:已启动新任务
[00:00:00.0060003] - 主要:IsCanceled = [False] IsFaulted = [False] IsCompleted = [False ]状态= [运行]
[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] Status = [Faulted]
[00:00:03.0111722] - Main:等待任务
[00:00:05.0112866] - Main:In Catch Block
[00:00:05.0112866] - Main:IsCanceled = [False] IsFaulted = [True] IsCompleted = [True] Status = [Faulted]
[00 :00:05.0112866] - 主要:在任务中收到异常[操作被取消.]

我从来没有看到Task.IsCanceled Set为true,我犯了错误或遗漏了一些明显的东西.我已就此问题进行了一些研究/搜索,但未能找到确凿的答案.

注意:有关StackOverFlow的相关问题 取消任务 任务IsCanceled为false,而我取消了 Task.IsCancelled不起作用

Sri*_*vel 8

我想你应该把它传递CancellationToken给构造函数OperationCanceledException.

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

TPL将检查两者CancellationToken是否相同,如果是,它将标记任务,因为Cancelled在您的情况下它不是,因此TPL假定您的任务未被取消.

甚至更好的使用ThrowIfCancellationRequested方法,就这么简单

ct.ThrowIfCancellationRequested();
Run Code Online (Sandbox Code Playgroud)