Threading gotcha in C#

So, as I mentioned last time, Gnome Do rocks. So much in fact that I’m looking for ways to contribute to the project. I haven’t been this excited about a piece of software in quite some time. The nerd in me is giddy.

My first contribution was to fix a bug I opened against the JIRA Gnome Do plugin (an awesome plugin by the way). The bug was causing Gnome Do to crash at startup if the JIRA server could not be reached. The fix was pretty easy. Wrap the code throwing the exception that was causing the crash in a try/catch block, and simply log and swallow the exception. Gnome Do calls the plugin every 5 minutes to update its index, so once you eventually connected to the web or logged in to your company’s network and can see your JIRA server, the plugin will be able to index the JIRA issues and all will be peachy.

I tested the fix, and it worked like a champ. However, I started to think to myself that it was very odd that Gnome Do let a rogue plugin take it down. I figured it would be a good idea to isolate all calls to the plugins, and wrap them all in try/catch blocks, as a means to protect the core application. I did some digging in the code, and I found that Gnome Do was already doing exactly that. So why on earth did an exception in the plugin take down the core app?

I did some more digging, and in the JIRA plugin, the update takes place in a separate thread. The author of the JIRA plugin, knowing that the call from Do to update the plugin’s index was a blocking call, and knowing that the communication with JIRA may take a little while, decided to do the communication with JIRA in a different thread, and immediately return control to Do. It was this thread that was throwing the exception when the JIRA server could not be reached. This puzzled me. Could it be possible that an uncaught exception in a separate thread can take down the entire application? “No way in hell” I thought to myself.

I was wrong.

With Google by my side, I searched the web for “c# thread exception” and found this free e-book about threading in C#. At the very bottom of the page, read this:

From .NET 2.0 onwards, an unhandled exception on any thread shuts down the whole application, meaning ignoring the exception is generally not an option. Hence a try/catch block is required in every thread entry method at least in production applications in order to avoid unwanted application shutdown in case of an unhandled exception.

Holy crap! I showed this to a co-worker, who quickly whipped up a Java program that spawned a thread that threw an exception, to see what happened. We were pretty sure that only that thread would die, and that the JVM would continue to chug along as normal. Thankfully, we were right.

Why on earth would .NET behave this way? The e-book says “From .NET 2.0 onwards”, so I’m assuming that this wasn’t the case in .NET 1.0. I wonder what the reason was for this change. Now, any .NET application that allows itself to be extended by plugins is now at risk of being taken down, at any time, by a rogue plugin! Yikes!

5 thoughts on “Threading gotcha in C#

  1. John,

    Cheers for the compliment on the plugin & thanks for the patch. As a Java developer myself (only dabbling in C#) I just took it for granted when a thread died due to a runtime exception that it’d kill the thread and not the application (hence the no global try/catch).

    As an aside, it looks like the gnome-do guys are trying to address this problem at the global level by invoking the plugins on separate processes then communicating via dbus:


  2. Andrew, I know what you mean. I was shocked to learn what uncaught exceptions in C# threads do to the application. I never would have guessed that they could take down the whole app.

    Thanks for the link to that bug. I’m curious to see how the gnome-do guys are going to address this.

  3. John, you can catch cross-thread C# exceptions using the AppDomain.CurrentDomain.UnhandledException event. Regards, Alan

Leave a Reply

Your email address will not be published. Required fields are marked *