1

I'd like to properly understand the consequences of failing to observe an exception thrown on a Task used in a fire and forget manner without exception handling.

Here's an extract from CLR via C#, Third Edition by Jeffry Richter: "[...] when a Task object is garbage collected, its Finalize method checks to see if the Task experienced an unobserved exception; if it has, Task's Finalize method throws [an exception]. Since you cannot catch an exception thrown by the CLR's finalizer thread, your process is terminated immediately."

I am writing some test code to bring about a termination but am unable to cause one.

Using the test code here, I am able to see the TaskScheduler.UnobservedTaskException handler being called. However, if I comment out the event handler subscription, the exception appears to be swallowed and does not bring about termination of the program.

I've tried this using the .NET Framework on both versions 4 and 4.8 with a Release build.

How do I demonstrate that failing to observe an exception thrown on a Task does indeed cause a crash?

aybe
  • 15,516
  • 9
  • 57
  • 105
fractor
  • 1,534
  • 2
  • 15
  • 30
  • 3
    Are you sure you've *actually* been running on .NET 4, rather than just targeting .NET 4 but running on 4.5+? As per https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler.unobservedtaskexception?view=net-6.0, you can configure this on a per-application basis in app.config, but the default is for it to *not* crash the app now. – Jon Skeet Dec 14 '21 at 08:56
  • Thanks @JonSkeet I think that's it. Adding `` does crash the program as expected. – fractor Dec 14 '21 at 09:14
  • Do you have time to post an answer here Jon? – fractor Dec 14 '21 at 09:18
  • No, you can add an answer yourself. – Jon Skeet Dec 14 '21 at 09:19

1 Answers1

1

The problem is correctly identified by Jon Skeet in his comment to the original post.

The best resource I found concerning this topic is by Stephen Toub.

tldr: "To make it easier for developers to write asynchronous code based on Tasks, .NET 4.5 changes the default exception behavior for unobserved exceptions. While unobserved exceptions will still cause the UnobservedTaskException event to be raised (not doing so would be a breaking change), the process will not crash by default. Rather, the exception will end up getting eaten after the event is raised, regardless of whether an event handler observes the exception. This behavior can be configured, though. A new CLR configuration flag may be used to revert back to the crashing behavior of .NET 4, e.g."

<configuration>
    <runtime>
        <ThrowUnobservedTaskExceptions enabled=”true”/>
    </runtime>
</configuration>
fractor
  • 1,534
  • 2
  • 15
  • 30
Clemens
  • 588
  • 6
  • 9