简体   繁体   中英

Why is Task.IsCanceled Not True?

I have a simple program here

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

} 

Sample Output
[00:00:00.0010000] - Main: Started
[00:00:00.0040002] - Main: Started New Task
[00:00:00.0060003] - Main: IsCanceled = [False] IsFaulted = [False] IsCompleted = [False] Status = [Running]
[00:00:00.0070004] - Task - [1]: Started
[00:00:01.0070576] - Main: Cancelling Task
[00:00:02.0071148] - Task - [1]: Cancellation Requested
[00:00:03.0111722] - Main: After Cancelling Task
[00:00:03.0111722] - Main: IsCanceled = [False] IsFaulted = [True] IsCompleted = [True] Status = [Faulted]
[00:00:03.0111722] - Main: Waiting For Task
[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] - Main: Received Exception In Task [The operation was canceled.]

I never see the Task.IsCanceled Set to true, am I making a mistake or missing something obvious. I have done a bit of research/searching on this issue but was not able to find a conclusive answer.

Note: Related Questions on StackOverFlow Cancellation of a task task IsCanceled is false, while I canceled Task.IsCancelled doesn't work

I suppose you should pass the CancellationToken to the constructor of OperationCanceledException .

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

TPL will check whether both CancellationToken are same, if so it will mark task as Cancelled in your case it is not and so TPL assumes your task is not cancelled.

or even better use ThrowIfCancellationRequested method, as simple as that

ct.ThrowIfCancellationRequested();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM