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.
From Exceptions in Managed Threads on MSDN:
In the .NET Framework version 2.0, thecommon language runtime allows mostunhandled exceptions in threads toproceed naturally. In most cases thismeans that the unhandled exceptioncauses the application to terminate.
This is a significant change from the.NET Framework versions 1.0 and 1.1,which provide a backstop for manyunhandled exceptions — for example,unhandled exceptions in thread poolthreads. See Change from PreviousVersions later in this topic.
As a temporary compatibility measure,administrators can place acompatibility flag in the section of the applicationconfiguration file. This causes thecommon language runtime to revert tothe behavior of versions 1.0 and 1.1.
<legacyUnhandledExceptionPolicy enabled="1"/>
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);}