How to Prevent an Exception in a Background Thread from Terminating an Application

How to prevent an exception in a background thread from terminating an application?

First, you really should try not to have exceptions thrown - and not handled - in a background thread. If you control the way your delegate is run, encapsulate it in a try catch block and figure a way to pass the exception information back to your main thread (using EndInvoke if you explicitly called BeginInvoke, or by updating some shared state somewhere).

Ignoring a unhandled exception can be dangerous. If you have a real un-handlable exception (OutOfMemoryException comes into mind), there's not much you can do anyway and your process is basically doomed.

Back to .Net 1.1, an unhandled exception in a backgroundthread would just be thrown to nowhere and the main thread would gladly plough on. And that could have nasty repercussions. So in .Net 2.0 this behavior has changed.

Now, an unhandled exception thrown in a thread which is not the main thread will terminate the process. You may be notified of this (by subscribing to the event on the AppDomain) but the process will die nonetheless.

Since this can be inconvenient (when you don't know what will be run in the thread and you are not absolutely sure it's properly guarded, and your main thread must be resilient), there's a workaround. It's intended as a legacy settings (meaning, it's strongly suggested you make sure you don't have stray threads) but you can force the former behavior this way :

Just add this setting to your service/application/whatever configuration file :

<configuration>
<runtime>
<!-- the following setting prevents the host from closing when an unhandled exception is thrown -->
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>

It doesn't seem to work with ASP.NET, though.

For more information (and a huge warning that this setting may not be supported in upcoming versions of the CLR) see http://msdn.microsoft.com/en-us/library/ms228965.aspx

Why does an unhandled exception in this background thread not terminate my process?

As PetSerAl points out in the comments section of the question, to get the exception information, it is mandatory to call EndInvoke from inside the completion callback as shown below.

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace OriginalCallStackIsLostOnRethrow
{
class Program
{
static void Main(string[] args)
{
try
{
A2();
// A3();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}

static void A2() { B2(); }
static void B2() { C2(); }
static void C2() { D2(); }
static void D2()
{
Action action = () =>
{
Console.WriteLine($"D2 called on worker #{Thread.CurrentThread.ManagedThreadId}. Exception will occur while running D2");
throw new DivideByZeroException();
};
action.BeginInvoke(ar =>
{
((Action)((ar as AsyncResult).AsyncDelegate)).EndInvoke(ar);

Console.WriteLine($"D2 completed on worker thread #{Thread.CurrentThread.ManagedThreadId}");
}, null);
}

static void A3() { B3(); }
static void B3() { C3(); }
static void C3() { D3(); }
static void D3()
{
Action action = () => { Console.WriteLine($"D2 called on worker #{Thread.CurrentThread.ManagedThreadId}."); };
action.BeginInvoke(ar =>
{
try
{
Console.WriteLine($"D2 completed on worker thread #{Thread.CurrentThread.ManagedThreadId}. Oh, but wait! Exception!");
throw new DivideByZeroException();
}
catch (Exception ex)
{
throw ex;
}
}, null);

}
}
}

This is weird, and it still remains a mystery as to why the stack trace does not show up if you were to place a try / catch block in the action that is executing asynchronously.

I am referring to the absence of the StackTrace, not the absence of a call stack. :-)

Sample Image

Stop background thread when exception is thrown in main thread

Before exiting the main thread, I would try cleaning up like this:

participant.delete_contained_entities(); 
DomainParticipantFactory.get_instance().delete_participant(participant);

[repeat for each participant you may have created...]

That should reclaim any resources (including threads) held/created by the participant.

Why unhandled exception in a background thread doesnt crash the app domain?

This is happening because the BeginInvoke uses ThreadPool internally and when ThreadPool any unhadled exceptions will be silence fail. However if you use a.EndInvoke then the unhadled exception will be throw at the EndInvoke method.

Note: as João Angelo stated that using ThreadPool methods directly "like ThreadPool.QueueUserWorkItems and UnsafeQueueUserWorkItem" will throw exceptions at 2.0 and above.

Why do AppDomain exceptions invariably terminate the application?

After doing some more searches on Google I found this very interesting explanation that was given to the same problem as described by Jeff Atwood on his blog.

Hi all,
Sorry for the confusion. This behavior is actually the design, though the design can be a little convoluted at times.

The first thing to understand is that the UnhandledException event is not an unhandled exception "handler". Registering for the event, contrary to what the documentation says :-(, does not cause unhandled exceptions to be handled. (Since then they wouldn't be unhandled, but I'll stop with the circular reasoning already...) The UnhandledException event simply notifies you that an exception has gone unhandled, in case you want to try to save state before your thread or application dies. FWIW, I have filed a bug to get the docs fixed.

Just to complicate things, in v1.0 and 1.1, an unhandled exception did not always mean that your application would die. If the unhandled exception occurred on anything other than the main thread or a thread that began its life in unmanaged code, the CLR ate the exception and allowed your app to keep going. This was generally evil, because what would often happen was, for example, that ThreadPool threads would silently die off, one by one, until your application wasn't actually doing any work. Figuring out the cause of this kind of failure was nearly impossible. This may be why Jeff thought it worked before...he just always saw crashes on non-main threads.

In v2.0, an unhandled exception on any thread will take down the application. We've found that it's tremendously easier to debug crashes than it is to debug hangs or the silent-stoppage-of-work problem described above.

BTW, on my 1.1 machine the example from MSDN does have the expected output; it's just that the second line doesn't show up until after you've attached a debugger (or not). In v2 we've flipped things around so that the UnhandledException event fires before the debugger attaches, which seems to be what most people expect.

Jonathan Keljo
CLR Exceptions PM
Jonathan Keljo on February 18, 2005 10:02 PM

However, I'm still interested in how the UI thread accomplishes the trick of allow you to have a catch-all handler for all UI thread exceptions.

Even more, I'm very interested in a way to disable the .NET JIT Debugging Dialog for my application only (without disabling it for the whole machine as seen here)

How to maintain a persistent background thread?

The real gotcha here is what you mean by go down in "or that they'll be brought back up if they do go down."

There are only two ways that I know of that a thread can go down without the entire process itself exiting in java:

  1. The run() method terminates, either via exception or finishing the run method normally (i.e., non-exceptionally).
  2. Thread.stop() is called on your thread.

Let's tackle (2) first - Thread.stop() is deprecated and is a big no-no in any well-behaving application. You can pretty much assume it is not going to be called, because if it is called, your application is already badly broken. Restarting any thread at this point may have undefined effects since your application is an inconsistent state.

So then for (1), you just have to ensure that run() doesn't terminate. It won't terminate normally because you've already set up an infinite loop. To stop it from terminating exceptionally, you can catch (Throwable t) and just keep looping (after logging the error appropriately).

Of course, a catch (Throwable t) without a subsequent rethrow is usually a code smell. It means you caught some time of unspecified error, and then decided to keep going anyways. The errors might range from the benign (e.g., a SockedClosedExcpetion because a remote client disconnected) to the unrecoverable (e.g., an OutOfMemoryError or something even worse). You should really ask yourself if you want this thread to continue in the face of any type of exception.

Your application could be an invalid state and may not be able to continue. One compromise would be to only catch subclasses of Exception and terminate the application on Error. A more conservative approach would be to terminate the application on any type of exception that you don't know how to handle (and treat it as a bug to be fixed).

asp.net Background Threads Exception Handling

You can always put a try/catch block around your worker thread at a very high level... like right when the thread starts. I'm assuming this is what you're doing already, or something like it. But just keep in mind that you definitely don't want to turn an unknown error into a silent unknown error, because then it's going to be much harder to track down when something goes wrong. Be sure you are logging the exception to the EventLog or your custom app log if you want to just catch it and forget it.

Like Aaronaught says, the application should die when something unexpected happens. But I don't see a problem with just letting your background thread exit/die instead of bringing down the whole application process (in fact, I don't think Aaron is correct here, it won't kill the entire process) I think your question can basically be translated as "is there something magical in ASP.NET that will suddenly solve issues I don't even know about yet?" and the answer to that of course, is no. But you already knew that. :)

How do I gracefully handle this exception in a background thread in a Windows service?

This isn't really an answer, more a comment, but I hate the poor formatting of code in comments.

Are you 100% sure the exception in that one statement is your only problem? I'm suggesting you add the following to your program:

     // Create AppDomain ProcessExit and UnhandledException event handlers
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

and, of course, the event handlers:

  /// <summary>
/// Method called when the process is exiting.
/// </summary>
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
// do some logging?
}

/// <summary>
/// Method called if an unhandled AppDomain exception occurs.
/// </summary>
private static void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
// do some logging?
}

You can't save the service at this point, but you might get some useful information.

Edit:

Just noticed I copy-and-pasted some code where the event handlers are marked "static", but that isn't necessary.



Related Topics



Leave a reply



Submit