在下面启用行//1
会导致程序崩溃,而不会打印“proc exit”,
但是在行//2
的情况下,将打印“proc exit”。在这两种情况下都会打印出“未处理的”btw。
为什么差异,一般的规则是什么?显然使用例如杀死应用程序任务管理器将阻止“proc退出”被打印,但除此之外,它没有被打印的情况是什么?
static void Main(string[] args)
{
Thread.GetDomain().UnhandledException +=
(sender, eventArgs) => Console.WriteLine("unhandled");
AppDomain.CurrentDomain.ProcessExit +=
(sender, eventArgs) => Console.WriteLine("proc exit");
//1 new Thread(_ => { throw new Exception(); }).Start();
//2 ThreadPool.QueueUserWorkItem(_ => { throw new Exception(); });
Thread.Sleep(1000);
return;
答案 0 :(得分:3)
这两种情况没有区别,很难解释为什么你会看到它。
使用编写的代码,永远不应引发AppDomain.ProcessExit事件。应该发生正常情况,CLR将异常传递给操作系统,并弹出Windows错误报告崩溃对话框。如果异常是程序崩溃的已知原因(它不会),那么它会与Microsoft服务器进行协商一段时间,然后在用户解除对话框时终止程序。所以没有ProcessExit事件。
您当然可以编写代码,以便引发ProcessExit 。它要求您不要将其留在操作系统中来处理它。你必须自己关闭程序。您可以使用AppDomain.UnhandledException事件处理程序自行显式终止程序。像这样:
Thread.GetDomain().UnhandledException += (s, e) => {
var ex = (Exception)e.ExceptionObject;
Console.WriteLine(ex.ToString());
Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(ex));
};
您可以选择如何终止该计划。我展示了Environment.Exit(),但您也可以考虑使用Environment.FailFast()来请求即时中止而不再运行任何代码。这更安全,但当然你也不会得到ProcessExit。
答案 1 :(得分:2)
请查看此博文:AppDomain.ProcessExit is not guaranteed to be called。引自帖子:
不保证会调用AppDomain.ProcessExit。这很美 有弹性,会处理你可能造成的常见事情 低信任IL(异常,内存不足等),但也有一些 事情(如粗鲁的进程关闭),inprocess事件永远不会 能够抵抗。
(...)
从进程内调用回调。如果这个过程粗鲁 退出,不会调用回调。粗鲁的常见来源 退出包括:
- 通过TaskManager或kernel32外部杀死!TerminateProcess。
- Stackoverflow处理程序消耗超过保护页面。
醇>ProcessExit事件就像告诉某人“请给我打电话 即将死亡“。如果死亡来得快,他们可能不会 把消息拿出来。
事实上,我已经尝试了你的代码,当取消注释第1行甚至第2行时,它从不打印“proc exit”! (我尝试在Visual Studio 2013中针对所有.NET版本进行编译)。当然,它会在没有抛出异常并且进程正常退出时打印它。 (编辑:如果我在发布模式下编译代码,我会看到“proc exit”消息,但是当我在调试模式下编译时却没有这样做。)
作为旁注,这里是您的代码的建议重构(未完全测试,可能不完整,但您明白了):
static void Main(string[] args)
{
Thread.GetDomain().UnhandledException +=
(sender, eventArgs) => Exiting((Exception)eventArgs.ExceptionObject);
AppDomain.CurrentDomain.ProcessExit +=
(sender, eventArgs) => Exiting(null);
//1 new Thread(_ => { throw new Exception(); }).Start();
//2 ThreadPool.QueueUserWorkItem(_ => { throw new Exception(); });
Thread.Sleep(1000);
return;
}
static void Exiting(Exception exception)
{
//Put common cleanup code here (or at the end of the method)
if(exception == null)
{
Console.WriteLine("normal proc exit");
}
else
{
Console.WriteLine("unhandled exception: " + exception.GetType().Name);
}
}