Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

.net

exception

People also ask

What are some of the ways an unhandled exceptions on thread pool threads will terminate the process?

Exceptions in Thread Pool threads Unhandled exceptions on thread pool threads terminate the process with 3 exceptions: A ThreadAbortException is thrown in a thread pool thread, because Abort was called. An AppDomainUnloadedException is thrown in a thread pool thread, because the application domain is being unloaded.

Does An exception occurred in one thread causes other threads to terminate?

Usually - no, exception in one thread does not kill another thread; unless....

What happens if exception occurs in thread?

An uncaught exception will cause the thread to exit. When it bubbles to the top of Thread. run() it will be handled by the Thread's UncaughtExceptionHandler. By default, this will merely print the stack trace to the console.

Which kind of threads has the ability to prevent the current application from terminating?

Foreground threads are those threads that keep running even after the application exits or quits. It has the ability to prevent the current application from terminating. The CLR will not shut down the application until all Foreground Threads have stopped.


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


From Joe Albahari's excellent threading article:

The .NET framework provides a lower-level event for global exception handling: AppDomain.UnhandledException. This event fires when there's an unhandled exception in any thread, and in any type of application (with or without a user interface). However, while it offers a good last-resort mechanism for logging untrapped exceptions, it provides no means of preventing the application from shutting down – and no means to suppress the .NET unhandled exception dialog.

In production applications, explicit exception handling is required on all thread entry methods. One can cut the work by using a wrapper or helper class to perform the job, such as BackgroundWorker (discussed in Part 3).


Keeping the answer short, yes, you do can prevent the runtime from terminating.

Here is a demo of the workaround:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

Essentially, you just did not let the runtime to show the "... program has stopped working" dialog.

In case you need to log the exception and silently exit, you can call Process.GetCurrentProcess().Kill();


    AppDomain.CurrentDomain.UnhandledException += (sender, e2) =>
    {
        Thread.CurrentThread.Join();
    };

But be careful, this code will freeze all the stack memory of the Thread and thread's managed object itself. However, if your application is in determined state (may be you threw LimitedDemoFunctionalityException or OperationStopWithUserMessageException) and you are not developing 24/7 application this trick will work.

Finally, I think MS should allow developers to override the logic of unhandled exceptions from the top of the stack.


Here is a great blog post about this problem: Handling "Unhandled Exceptions" in .NET 2.0

IMO it would be right to handle exceptions in background threads manually and re-throw them via callback if necessary.

delegate void ExceptionCallback(Exception ex);

void MyExceptionCallback(Exception ex)
{
   throw ex; // Handle/re-throw if necessary
}

void BackgroundThreadProc(Object obj)
{
   try 
   { 
     throw new Exception(); 
   }
   catch (Exception ex)
   { 
     this.BeginInvoke(new ExceptionCallback(MyExceptionCallback), ex); 
   }
}

private void Test()
{
   ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundThreadProc));
}