1

I have the below test program which sets up the UnobservedTaskException however the OnTaskException method is never executed. Any ideas?

NOTE:

If I remove the "for loop" then everything works as expected.

static void Main()
{
    SetupUnobservedTaskExceptionHandling();

    Task.Factory.StartNew(() =>
    {
        var counter = 5;
        for (; counter > 0; counter--)
        {
            Console.WriteLine(counter);
            Thread.Sleep(1000);
        }
        throw new InvalidCastException("I threw up!");
    });

    GC.Collect();
    GC.WaitForPendingFinalizers();
    Console.ReadLine();
}

private static void SetupUnobservedTaskExceptionHandling()
{
    TaskScheduler.UnobservedTaskException += OnTaskException;
}

private static void OnTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
    Console.WriteLine("Error!" + e.Exception);
    e.SetObserved();
}
i3arnon
  • 113,022
  • 33
  • 324
  • 344
MaYaN
  • 6,683
  • 12
  • 57
  • 109
  • 1
    This is not a duplicate of [TAP global exception handler](http://stackoverflow.com/q/22369179/885318), it's simply a bug. – i3arnon Jul 21 '14 at 22:41
  • 1
    @I3arnon: the accepted answer to that question explains that the event is not fired unless the task is collected. That pretty much explains why the loop in this question delays the exception enough to pass the `GC.Collect` call. – vgru Jul 21 '14 at 22:47
  • @Groo, I agree this is a duplicate of http://stackoverflow.com/q/22369179/1768303, but I decided to withdraw my vote. It closed the question instantaly, which in this case might be too much power for a single vote :) – noseratio Jul 21 '14 at 22:51
  • 1
    @Groo It doesn't. The OP clearly knows when the `UnobservedTaskException` should be raised and calls `GC.Collect` to raise it. Her/His question is about this specific block of code (that had a bug in it), which has no solution in the other question. – i3arnon Jul 21 '14 at 22:53
  • 2
    I have to agree with I3arnon, I am familiar with how observed/unobserved exceptions bubble up, the problem with this piece of code was that by the time GC had finished collecting, the Task had not thrown any exceptions. My motivation for writing this test code was to observe the behaviour of the exception when it is un-obvserved AND collected by the GC. – MaYaN Jul 21 '14 at 22:57

1 Answers1

2

You are not waiting for the task to finish executing. That means that your app will end before the task throws an exception.

If you simply add a Thread.Sleep and let the task throw the exception you will be notified:

private static void Main()
{
    SetupUnobservedTaskExceptionHandling();

    Task.Factory.StartNew(() =>
    {
        var counter = 5;
        for (; counter > 0; counter--)
        {
            Console.WriteLine(counter);
            Thread.Sleep(1000);
        }
        throw new InvalidCastException("I threw up!");
    });

    Thread.Sleep(10000);

    GC.Collect();
    GC.WaitForPendingFinalizers();
    Console.ReadLine();
}
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • very interesting. Can you plz explain why removing the for loop also fixes this? I am very confused by this behaviour. – MaYaN Jul 21 '14 at 22:36
  • @MaYaN It isn't the for loop.. it's the `Thread.Sleep(1000);` inside it. When you remove it the task throws immediately just before you call `GC.Collect` – i3arnon Jul 21 '14 at 22:38
  • 1
    Perfect, it makes complete sense, I previously had a Thread.Sleep(1000) just before the GC.Collect which is clearly less than the time it takes for the loop to finish (5000) which means by the time GC collects, the Task actually hasn't thrown an exception. – MaYaN Jul 21 '14 at 22:40