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

14,163

Solution 1

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.

Solution 2

From Exceptions in Managed Threads on MSDN:

In the .NET Framework version 2.0, the common language runtime allows most unhandled exceptions in threads to proceed naturally. In most cases this means that the unhandled exception causes the application to terminate.

This is a significant change from the .NET Framework versions 1.0 and 1.1, which provide a backstop for many unhandled exceptions — for example, unhandled exceptions in thread pool threads. See Change from Previous Versions later in this topic.

As a temporary compatibility measure, administrators can place a compatibility flag in the section of the application configuration file. This causes the common language runtime to revert to the behavior of versions 1.0 and 1.1.

<legacyUnhandledExceptionPolicy enabled="1"/>

Solution 3

Normally with asynchronous delegates if the delegated method throws an exception the thread is terminated and the exception will be thrown again in the calling code only when you call EndInvoke.

This is why when using an asynchronous delegate (BeginInvoke) you should always call EndInvoke. Also, this should not be confused with Control.BeginInvoke which can be called in a fire and forget manner.

Earlier I said normally, because there is a possibility for you to state that the exception should be ignored if the delegate method returns void. To do this you need to mark the method with the OneWay attribute.

If you run the following example, you will only get an exception when calling willNotIgnoreThrow.EndInvoke.

static void Throws()
{
    Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);

    throw new ApplicationException("Test 1");
}

[OneWay]
static void ThrowsButIsIgnored()
{
    Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);

    throw new ApplicationException("Test 2");
}

static void Main(string[] args)
{
    Console.WriteLine("Main: {0}", Thread.CurrentThread.ManagedThreadId);

    var willIgnoreThrow = new Action(ThrowsButIsIgnored);
    var result1 = willIgnoreThrow.BeginInvoke(null, null);

    Console.ReadLine();
    willIgnoreThrow.EndInvoke(result1);

    Console.WriteLine("============================");

    var willNotIgnoreThrow = new Action(Throws);
    var result2 = willNotIgnoreThrow.BeginInvoke(null, null);

    Console.ReadLine();
    willNotIgnoreThrow.EndInvoke(result2);
}
Share:
14,163
Boppity Bop
Author by

Boppity Bop

I hate networking, social networking and all sorts of reliance on other people. including asking for help on SO.

Updated on June 26, 2022

Comments

  • Boppity Bop
    Boppity Bop almost 2 years

    I am completely puzzled. I was so sure that .NET shuts the whole application domain if there is uncaught exception in a thread that I never tested this.

    However I just tried the following code and it doesn't fail... Could anyone please explain why?

    (Tried in .NET 4 and 3.5)

    static void Main(string[] args)
    {
        Console.WriteLine("Main thread {0}", Thread.CurrentThread.ManagedThreadId);
    
        Action a = new Action(() =>
        {
            Console.WriteLine("Background thread {0}", Thread.CurrentThread.ManagedThreadId);
    
            throw new ApplicationException("test exception");
        });
    
        a.BeginInvoke(null, null);
    
        Console.ReadLine();
    }
    
  • Boppity Bop
    Boppity Bop almost 13 years
    Jon thank you for the effort but you failed to read the question.. The question is exactly WHY it DID NOT fail. Cheers
  • Boppity Bop
    Boppity Bop almost 13 years
    you are mixing up a 'background thread' and BackgroundWorker class.
  • Bek Raupov
    Bek Raupov almost 13 years
    not really, BackgroundWorker creates Background thread. The only difference between normal thread and back thread is that back thread doesnt hold up your appliaction from close down, while you have to wait for normal thread to finish its work.
  • user1877401
    user1877401 almost 13 years
    I understood the question, I'm telling you what the official guidance is on it, and giving you some possible reasons (framework version, config setting), and some further reading to understand what is going on :)
  • Eric Lippert
    Eric Lippert almost 13 years
    @Bobb: Is snappish criticism how you always respond to strangers who try to help you for free? How does that work out for you?