2

I made a task to count the number, the task will receive the cancel request after 5 seconds, however after the task is cancelled I checked the status of task. The status of task is still running. Why? The sample code is below:

  var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);//Request Cancel after 5 seconds
        var newTask = Task.Factory.StartNew(state =>
        {
            try
            {
                int i = 1;
                var token = (System.Threading.CancellationToken)state;
                while (true)
                {
                    Console.WriteLine(i);
                    i++;
                    Thread.Sleep(1000);
                    token.ThrowIfCancellationRequested();
                }

            }
            catch
            {

            }
            finally
            {
            }


        }, cts.Token, cts.Token);


        try
        {
            newTask.Wait(10000, cts.Token);

        }
        catch
        {
            Console.WriteLine("Catch:"+ newTask.Status);//The status is Running
        }
        Console.ReadLine();
LoremIpsum
  • 1,652
  • 18
  • 27

2 Answers2

3

There are two problems with that code:

  1. token.ThrowIfCancellationRequested() does exactly what the name says, it throws an exception. Since you use a try/catch block to catch it you might as well just return from the task. The task state after the "cancellation" won't be Faulted because the framework doesn't see the exception.
  2. You are using Wait with the same cancellation token. This means as soon as the 5 seconds are done the Wait will be cancelled and the catch block will be executed. At this time the task may or may not be cancelled.

What you should do is getting rid of the try/catch/finally in the task's body and remove the token from the call to Wait: newTask.Wait(10000).


Full code:

var cts = new CancellationTokenSource();
cts.CancelAfter(5000);//Request Cancel after 5 seconds
var newTask = Task.Factory.StartNew(state =>
{
    int i = 1;
    var token = (System.Threading.CancellationToken)state;
    while (true)
    {
        Console.WriteLine(i);
        i++;
        Thread.Sleep(1000);
        token.ThrowIfCancellationRequested();
    }
}, cts.Token, cts.Token);

try
{
    newTask.Wait(10000);
}
catch
{
    Console.WriteLine("Catch:"+ newTask.Status);
}

LINQpad output:

1
2
3
4
5
Catch:Canceled

Dirk
  • 10,668
  • 2
  • 35
  • 49
  • I try your suggestion,but the this time the program is paused due to the exception thrown by the task body(because it has not been catch),so i can not inspect the status of the task,i`m afraid that i may have some misunderstanding,can you give me the code? – LoremIpsum Apr 28 '15 at 11:51
  • I copy your code and run it in the visual studio 2013 as a console application,but i don`t have the output as you are,my program is paused due to the exception in the task body – LoremIpsum Apr 28 '15 at 12:05
  • @BlueSteel This can happen if you set the debugging to break when an exception is thrown. Reseting the exception settings removes that (Debug, Exceptios, Reset all), and the debugger only breaks if an exception is uncaught. – Dirk Apr 28 '15 at 12:09
  • http://stackoverflow.com/questions/16921984/stop-visual-studio-from-breaking-on-exception-in-tasks offer a solution,my problem is solved .Thanks a lot – LoremIpsum Apr 28 '15 at 12:17
0

Try to print status to console outside of the catch block. At the point you printing status CancellationPended and Exception throwed, but the state changes right after the catch block execution is finished.

Eldar
  • 104
  • 6
  • You are right. There is no repeatable behavior: some runs print status "RanToCompleted", some runs print "Running". – Eldar Apr 28 '15 at 06:03