Alex Rivera | Logout

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

Asked 2011-06-24T08:52:36.380
16

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();
}
Edit
Report

2 Answers

10

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.

answered 2011-06-24T09:38:41.710
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);
}
answered 2011-06-24T09:53:36.120

Your Answer