Why task's status is Faulted instead of Canceled?

74 Views Asked by At

I was experimenting different ways of cancellations. Here you'll see 5 different approaches and there is no doubt about the first four approaches. (These are commented but kept to avoid discussion on them). I'd like to know about the last approach(approach-5 shown below):

using static System.Console;

WriteLine("Simple cancellation demonstration.");

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

// This token is used for a follow-up question
var token2 = tokenSource.Token;

var printTask = Task.Run
 (
  () =>
  {
      // A loop that runs 100 times
      for (int i = 0; i < 100; i++)
      {
          // Approach-1 :(Will cause RanToCompletion)
          //if (token.IsCancellationRequested)
          //{
          //    WriteLine("Cancelling the print activity.");
          //    // Do some cleanups, if required
          //    return;
          //}
          //// Approach-2
          //if (token.IsCancellationRequested)
          //{
          //    WriteLine("Cancelling the print activity.");
          //    // Do some cleanups, if required
          //    throw new OperationCanceledException(token);
          //}
          // Approach-3
          // token.ThrowIfCancellationRequested();

          //// Approach 4
          //if (token.IsCancellationRequested)
          //{
          //    // Do some cleanups, if required
          //    token.ThrowIfCancellationRequested();
          //}
          // Approach 5
          if (token.IsCancellationRequested)
          {
              WriteLine("Cancelling the print activity.");
                throw new OperationCanceledException("Raised a  cancellation request"); // Causing Faulted state
              // throw new OperationCanceledException(); // Causing Faulted state also              
          }

          WriteLine($"{i}");
          // Imposing the sleep to make some delay
          Thread.Sleep(500);
      }
  }, token
);

WriteLine("Enter c to cancel the task.");
char ch = ReadKey().KeyChar;
if (ch.Equals('c'))
{
    WriteLine("\nTask cancellation requested.");
    tokenSource.Cancel();
}

// Wait till the task finishes the execution[ Not for production code]
while (!printTask.IsCompleted) { }

WriteLine($"The final status of printTask is: {printTask.Status}");
WriteLine("End of the main thread.");
Here is a sample output:
    Simple cancellation demonstration.
    Enter c to cancel the task.
    0
    1
    2
    c
    Task cancellation requested.
    Cancelling the print activity.
    The final status of printTask is: Faulted
    End of the main thread.

So, I can see when I do not pass the token as a parameter (inside the exception), the state is Faulted,but not canceled. Now I have the following question:

Is this an expected behavior?

Additional note: I have seen the online link:https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-cancellation states:

If the token's IsCancellationRequested property returns false or if the exception's token doesn't match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state.

But this does not clear the doubt yet.Please let me know what are the basics that I am missing here?

Should I conclude that raising an OperationCanceledException without the token will always cause a Faulted state?

1

There are 1 best solutions below

4
Robert McKee On BEST ANSWER

It's because token and token2 are the same token.

var areSame = object.ReferenceEquals(token, token2);
Console.WriteLine($"token is the same as token2: {areSame}");