如何防止后台线程中的exception终止应用程序?

我可以连接到AppDomain.CurrentDomain.UnhandledException从后台线程中loggingexception,但是如何防止它们终止运行时呢?

首先,你应该尽量避免在后台线程中抛出exception(而不是处理)。 如果你控制委托运行的方式,把它封装在一个try catch块中,并设法将exception信息传回给你的主线程(如果你明确地调用了BeginInvoke,或者通过更新某个共享状态,使用EndInvoke)。

忽略未处理的exception可能是危险的。 如果你有一个真正的不可处理的exception(OutOfMemoryException),那么你不能做任何事情,你的过程基本上是注定的。

回到.net 1.1,在后台线程中的一个未处理的exception将被抛到无处,主线程将很乐意继续。 这可能会产生恶劣的影响。 所以在.Net 2.0中这个行为已经改变了。

现在,在一个不是主线程的线程中抛出一个未处理的exception将终止该进程。 您可能会收到通知(通过订阅AppDomain上的事件),但这个过程将会死亡。

由于这可能是不方便的(当你不知道在线程中运行什么,并且你不能确定它是否被妥善保护,并且你的主线程必须是有弹性的),这是一个解决方法。 它的目的是作为一个传统的设置(这意味着,强烈build议你确保你没有stream浪的线程),但你可以强制这样的前一个行为:

只需将此设置添加到您的服务/应用程序/任何configuration文件:

 <configuration> <runtime> <!-- the following setting prevents the host from closing when an unhandled exception is thrown --> <legacyUnhandledExceptionPolicy enabled="1" /> </runtime> </configuration> 

不过,它似乎并不适用于ASP.NET。

有关更多信息(以及在即将发布的CLR版本中可能不支持此设置的巨大警告),请参阅http://msdn.microsoft.com/zh-cn/library/ms228965.aspx

从Joe Albahari的优秀的线程文章:

.NET框架为全局exception处理提供了一个较低级别的事件:AppDomain.UnhandledException。 当任何线程和任何types的应用程序(带或不带用户界面)中都存在未处理的exception时,将触发此事件。 然而,尽pipe它提供了一个很好的logging未处理的exception的最后机制,但是它并没有提供防止应用程序closures的方法,也没有办法压制.NET未处理的exception对话框。

在生产应用程序中,所有线程input方法都需要显式exception处理。 可以使用包装器或帮助器类来执行作业,例如BackgroundWorker(第3部分中讨论)。

保持答案简短,是的,你可以防止运行时终止。

以下是解决方法的演示:

 class Program { void Run() { AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); Console.WriteLine("Press enter to exit."); do { (new Thread(delegate() { throw new ArgumentException("ha-ha"); })).Start(); } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); Console.WriteLine("last good-bye"); } int r = 0; void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Interlocked.Increment(ref r); Console.WriteLine("handled. {0}", r); Console.WriteLine("Terminating " + e.IsTerminating.ToString()); Thread.CurrentThread.IsBackground = true; Thread.CurrentThread.Name = "Dead thread"; while (true) Thread.Sleep(TimeSpan.FromHours(1)); //Process.GetCurrentProcess().Kill(); } static void Main(string[] args) { Console.WriteLine("..."); (new Program()).Run(); } } 

本质上,你只是没有让运行时显示“…程序已停止工作”对话框。

如果您需要loggingexception并以无提示退出,则可以调用Process.GetCurrentProcess().Kill();

这里有一个关于这个问题的好博客文章: 在.NET 2.0中处理“未处理的exception”

海事组织是正确的手动处理后台线程的exception,如果有必要,通过callback重新抛出它们。

 delegate void ExceptionCallback(Exception ex); void MyExceptionCallback(Exception ex) { throw ex; // Handle/re-throw if necessary } void BackgroundThreadProc(Object obj) { try { throw new Exception(); } catch (Exception ex) { this.BeginInvoke(new ExceptionCallback(MyExceptionCallback), ex); } } private void Test() { ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundThreadProc)); }