DongWei DongWei - 7 days ago 6
C# Question

Can "ThrowIfCancellationRequested" not be caught by TaskScheduler_UnobservedTaskException?

I have a very very strange problem, and here's my codes now:

namespace TaskParallelTest
{
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;

public class Program
{
static Program()
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
private static void DoPrint(int id, CancellationToken cToken)
{
Thread.Sleep(100);
if (!cToken.IsCancellationRequested)
{
Console.WriteLine("Id is:" + id + ";Current State:" + cToken.IsCancellationRequested);
cToken.Register(() => Console.WriteLine("Rollback for:" + id));
}
}
static void Main(string[] args)
{
CancellationTokenSource cTokenSource = new CancellationTokenSource();

Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
cTokenSource.Token.ThrowIfCancellationRequested();
DoPrint(i, cTokenSource.Token);
}
}, cTokenSource.Token);

Random r = new Random();

Thread.Sleep(400);
cTokenSource.Cancel(true);
Thread.Sleep(10000);
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("OK");
Console.ReadLine();
}

private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText("C:\\Resume\\Error.txt", e.Exception.StackTrace);
e.SetObserved();
}
}
}


What makes me feel mad is why the event of "UnobservedTaskException" cannot be caught? I used GC.Collect() and Thread.Sleep(), but without any help……?

Sometimes, the "Error.txt" wasn't created, and sometimes, the file created without anything there....?

enter image description here

Evk Evk
Answer

If OperationCanceledException is thrown for particular token, and this is the same token you passed when creating the task - it is not treated as unhandled\unobserved exception, because it's just normal, expected cancellation flow. This exception will instead just set task state to Cancelled. That is so in your case too:

var task = Task.Run(() =>
{
   for (int i = 1; i < 6; i++)
   {
       // this exception is associated with cTokenSource.Token
       cTokenSource.Token.ThrowIfCancellationRequested();
       DoPrint(i, cTokenSource.Token);
   }
}, cTokenSource.Token); // and this is the same token you pass when creating a task

If that were not the case (for example, you pass different token when creating a task) - exception will be intercepted by UnobservedTaskException handler.

Question is: why at all you want this exception to be treated as unobserved? You expected the task can be cancelled, you then cancel it, it's now in Cancelled state. Nothing unobserved\unhandled.

Comments