![](/img/trans.png)
[英]how to crash the main process if there is unhandled exception inside background thread
[英]Why unhandled exception in a background thread doesnt crash the app domain?
我完全不解。 如果在我从未测试过的线程中存在未捕获的异常,我确信.NET会关闭整个应用程序域。
但是,我只是尝试了下面的代码,它没有失败......任何人都可以解释为什么?
(在.NET 4和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();
}
发生这种情况是因为BeginInvoke
内部使用ThreadPool
而当ThreadPool
任何未处理的异常将是静默失败。 但是,如果使用a.EndInvoke
,则将在EndInvoke
方法中抛出未处理的异常。
注意:如João Angelo
说,使用ThreadPool
方法直接“像ThreadPool.QueueUserWorkItems
和UnsafeQueueUserWorkItem
”将在2.0及以上抛出异常。
从MSDN上的托管线程中的例外 :
在.NET Framework 2.0版中,公共语言运行库允许线程中大多数未处理的异常自然地进行。 在大多数情况下,这意味着未处理的异常会导致应用程序终止。
这是.NET Framework版本1.0和1.1的重大变化,它为许多未处理的异常提供了支持 - 例如,线程池线程中的未处理异常。 请参阅本主题后面的“从先前版本更改”。
作为临时兼容性措施,管理员可以在应用程序配置文件的部分中放置兼容性标志。 这会导致公共语言运行库恢复到版本1.0和1.1的行为。
<legacyUnhandledExceptionPolicy enabled="1"/>
通常使用异步委托,如果委托方法抛出异常,则线程终止,并且只有在调用EndInvoke
时才会在调用代码中再次抛出异常。
这就是使用异步委托( BeginInvoke
)时应始终调用EndInvoke
。 此外,这不应与Control.BeginInvoke
混淆,后者可以以一种火灾和忘记方式调用。
我之前通常说过,因为如果委托方法返回void,你有可能声明应该忽略该异常。 为此,您需要使用OneWay
属性标记方法。
如果运行以下示例,则在调用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);
}
因为对给定线程的异常抛出会保留在那里,除非它被引导回主线程。
这就是backgroundWorker为你做的,如果你在BackgroundWorker的线程中有异常,它会在主线程上重新抛出。
a.BeginInvoke(null, null);
这会产生异步调用,这会创建另一个执行此操作的线程
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.