5

What is the use of CancellationToken's IsCancellationRequested property? Consider below code

static void Main(string[] args)
{
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;
    Console.WriteLine("Press Enter to Start.\nAgain Press enter to finish.");
    Console.ReadLine();
    Task t = new Task(() =>
    {
        int i = 0;
        while (true)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Task Cancel requested");
                break;
            }
            Console.WriteLine(i++);
        }
    }, token);

    t.Start();

    // wait for input before exiting
    Console.ReadLine();
    tokenSource.Cancel();
    if(t.Status==TaskStatus.Canceled)
        Console.WriteLine("Task was cancelled");
    else
        Console.WriteLine("Task completed");
}

I find that on rare occasions code inside if block doesn't run. If so what is the use of polling to see if cancellation is requested?

svick
  • 236,525
  • 50
  • 385
  • 514
Sat
  • 161
  • 1
  • 2
  • 8
  • 2
    I suspect your diagnostics are off. It should work fine. What *exactly* do you observe in the failure case? Is it possible that there's just a delay while your output buffer catches up? – Jon Skeet Feb 23 '13 at 08:14
  • some times i dont see the output "Task Cancel requested" in the console when i hit enter the 2nd time. But it is very rare. – Sat Feb 23 '13 at 08:23
  • I suspect it's just a race condition in console output (although that's a little odd). It's clearly always going through that code, otherwise the task wouldn't stop. In the failure cases, does the program still finish? – Jon Skeet Feb 23 '13 at 08:36
  • i can always see "Task Completed" output in the window and program completes when i hit enter – Sat Feb 23 '13 at 08:41
  • 2
    In that case it's *definitely* just a diagnostic problem. There's no way the task would complete *without* noticing cancellation (leaving checked overflow aside) so it's just a matter of the console output. – Jon Skeet Feb 23 '13 at 08:54
  • hmm ok..i will test some other way and come back if i find some thing abnormal – Sat Feb 23 '13 at 09:06

1 Answers1

8

The problem with your code is that you don't wait for the Task to finish. So, what can happen is this:

  1. You call Cancel().
  2. You check Status, which returns Running.
  3. Confusingly, you write “Task completed” when the Task is still running.
  4. Main() completes, application exits.
  5. (At this point, IsCancellationRequested would be checked from the background thread. But that never happens, since the application already exited.)

To fix that, add t.Wait() after you call Cancel().

But that still won't fix your program completely. You need to tell the Task that it was canceled. And you do that by throwing OperationCanceledException that contains the CancellationToken (the usual way to do that is to call ThrowIfCancellationRequested()).

One issue with that is that Wait()ing on a Task that was canceled will throw an exception, so you will have to catch that.

svick
  • 236,525
  • 50
  • 385
  • 514
  • thx for your answer can you please explain little bit what is 'At this point, IsCancellationRequested would be checked from the background thread.' – Sat Feb 23 '13 at 12:17
  • @Sat I'm not sure what's there to explain. The timing of operations on different threads is unpredictable, so this is one possible way the operations can happen. – svick Feb 23 '13 at 12:20
  • ok. t.Wait() works. Back ground thread exits as soon as main thread does. am i right? so in my prevoius case main might have exited before background could reach Console.Write... – Sat Feb 23 '13 at 12:58
  • @Sat Yeah, application exists as soon as all foreground threads exit. And if some background threads are executing at the point, they are forcibly closed too. – svick Feb 23 '13 at 13:15