1

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

Community
  • 1
  • 1
Sonu
  • 11
  • 1
  • 2

1 Answers1

8

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();
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • So its a two way process than, after the `CancellationTokenSource.Cancel` the task should explicitly acknowledge the cancellation via the `CancellationToken`, Throwing a `OperationCanceledException` is not sufficient. This clears a lot of things. Thanks. – Sonu Dec 26 '13 at 14:39
  • 1
    Yes of course and that's why microsoft calls this pattern as *cooperative cancellation*. Check [this](http://msdn.microsoft.com/en-us/library/dd997396%28v=vs.110%29.aspx) out, read first two bullet points that explains the thing :) – Sriram Sakthivel Dec 26 '13 at 14:50