我完全不解。如果在我从未测试过的线程中存在未捕获的异常,我确信.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();
}
答案 0 :(得分:9)
这种情况正在发生,因为BeginInvoke
在内部使用ThreadPool
,而当ThreadPool
任何未经编码的例外情况都会导致沉默失败。但是,如果您使用a.EndInvoke
,那么未加工的异常将以EndInvoke
方法抛出。
注意:正如João Angelo
所述,直接使用ThreadPool
方法“如ThreadPool.QueueUserWorkItems
和UnsafeQueueUserWorkItem
”会在2.0及更高版本处抛出异常。
答案 1 :(得分:6)
来自MSDN上的Exceptions in Managed Threads:
在.NET Framework 2.0版中, 公共语言运行时允许最多 线程中未处理的异常 自然地进行。在大多数情况下这个 表示未处理的异常 导致应用程序终止。
这是一个重大变化 .NET Framework版本1.0和1.1, 这为许多人提供了支持 未处理的例外 - 例如, 线程池中未处理的异常 线程。请参阅从上一个更改 本主题后面的版本。
作为临时兼容措施, 管理员可以放置一个 兼容性标志 申请部分 配置文件。这导致了 要恢复的公共语言运行库 版本1.0和1.1的行为。
<legacyUnhandledExceptionPolicy enabled="1"/>
答案 2 :(得分:3)
通常使用异步委托,如果委托方法抛出异常,则线程终止,并且当您调用EndInvoke
时,将仅在调用代码 中再次抛出异常。
这就是为什么在使用异步委托(BeginInvoke
)时,您应该始终调用EndInvoke
。此外,这不应与Control.BeginInvoke
相混淆,OneWay
可以用火与忘记的方式调用。
之前我通常说过,因为如果委托方法返回void,你有可能声明应该忽略异常。为此,您需要使用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);
}
时收到异常。
{{1}}
答案 3 :(得分:0)
因为对给定线程的异常抛出会保留在那里,除非它被引导回主线程。
这就是backgroundWorker为你做的,如果你在BackgroundWorker的线程中有异常,它会在主线程上重新抛出。
a.BeginInvoke(null, null);
这会产生异步调用,这会创建另一个执行此
的线程