Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancelling a Task is throwing an exception

From what I've read about Tasks, the following code should cancel the currently executing task without throwing an exception. I was under the impression that the whole point of task cancellation was to politely "ask" the task to stop without aborting threads.

The output from the following program is:

Dumping exception

[OperationCanceledException]

Cancelling and returning last calculated prime.

I am trying to avoid any exceptions when cancelling. How can I accomplish this?

void Main() {     var cancellationToken = new CancellationTokenSource();      var task = new Task<int>(() => {         return CalculatePrime(cancellationToken.Token, 10000);     }, cancellationToken.Token);      try     {         task.Start();         Thread.Sleep(100);         cancellationToken.Cancel();         task.Wait(cancellationToken.Token);              }     catch (Exception e)     {         Console.WriteLine("Dumping exception");         e.Dump();     } }  int CalculatePrime(CancellationToken cancelToken, object digits) {       int factor;      int lastPrime = 0;      int c = (int)digits;      for (int num = 2; num < c; num++)     {          bool isprime = true;         factor = 0;           if (cancelToken.IsCancellationRequested)         {             Console.WriteLine ("Cancelling and returning last calculated prime.");             //cancelToken.ThrowIfCancellationRequested();             return lastPrime;         }          // see if num is evenly divisible          for (int i = 2; i <= num/2; i++)         {              if ((num % i) == 0)             {                              // num is evenly divisible -- not prime                  isprime = false;                  factor = i;              }         }           if (isprime)         {             lastPrime = num;         }     }      return lastPrime; } 
like image 465
Razor Avatar asked Sep 08 '11 04:09

Razor


People also ask

What is task Cancelled exception?

There's 2 likely reasons that a TaskCanceledException would be thrown: Something called Cancel() on the CancellationTokenSource associated with the cancellation token before the task completed. The request timed out, i.e. didn't complete within the timespan you specified on HttpClient. Timeout .

Does CancellationToken throw exception?

An exception thrown by this operation represents cancellation only when its type inherits from OperationCanceledException and when the CancellationToken. IsCancellationRequested property is true .

How do you handle a cancellation token?

The wait handle of the cancellation token will become signaled in response to a cancellation request, and the method can use the return value of the WaitAny method to determine whether it was the cancellation token that signaled. The operation can then just exit, or throw a OperationCanceledException, as appropriate.


1 Answers

I am trying to avoid any exceptions when cancelling.

You shouldn't do that.

Throwing OperationCanceledException is the idiomatic way that "the method you called was cancelled" is expressed in TPL. Don't fight against that - just expect it.

It's a good thing, because it means that when you've got multiple operations using the same cancellation token, you don't need to pepper your code at every level with checks to see whether or not the method you've just called has actually completed normally or whether it's returned due to cancellation. You could use CancellationToken.IsCancellationRequested everywhere, but it'll make your code a lot less elegant in the long run.

Note that there are two pieces of code in your example which are throwing an exception - one within the task itself:

cancelToken.ThrowIfCancellationRequested() 

and one where you wait for the task to complete:

task.Wait(cancellationToken.Token); 

I don't think you really want to be passing the cancellation token into the task.Wait call, to be honest... that allows other code to cancel your waiting. Given that you know you've just cancelled that token, it's pointless - it's bound to throw an exception, whether the task has actually noticed the cancellation yet or not. Options:

  • Use a different cancellation token (so that other code can cancel your wait independently)
  • Use a time-out
  • Just wait for as long as it takes
like image 97
Jon Skeet Avatar answered Sep 22 '22 09:09

Jon Skeet