有趣的问题;使用ILSpy,让我们看看有什么Application.Exit()
作用:
我们看到关键方法是ExitInternal
private static bool ExitInternal()
{
bool flag = false;
lock (Application.internalSyncObject)
{
if (Application.exiting)
{
return false;
}
Application.exiting = true;
try
{
if (Application.forms != null)
{
foreach (Form form in Application.OpenFormsInternal)
{
if (form.RaiseFormClosingOnAppExit())
{
flag = true;
break;
}
}
}
if (!flag)
{
if (Application.forms != null)
{
while (Application.OpenFormsInternal.Count > 0)
{
Application.OpenFormsInternal[0].RaiseFormClosedOnAppExit();
}
}
Application.ThreadContext.ExitApplication();
}
}
finally
{
Application.exiting = false;
}
}
return flag;
}
如果一切顺利,应用程序将首先关闭所有表单,然后关闭它错过的所有表单,最后,它会调用Application.ThreadContext.ExitApplication();
作为 ExitApplication 的一部分,我们看到了清理:
private static void ExitCommon(bool disposing)
{
lock (Application.ThreadContext.tcInternalSyncObject)
{
if (Application.ThreadContext.contextHash != null)
{
Application.ThreadContext[] array = new Application.ThreadContext[Application.ThreadContext.contextHash.Values.Count];
Application.ThreadContext.contextHash.Values.CopyTo(array, 0);
for (int i = 0; i < array.Length; i++)
{
if (array[i].ApplicationContext != null)
{
array[i].ApplicationContext.ExitThread();
}
else
{
array[i].Dispose(disposing);
}
}
}
}
}
// System.Windows.Forms.ApplicationContext
/// <summary>Terminates the message loop of the thread.</summary>
/// <filterpriority>1</filterpriority>
public void ExitThread()
{
this.ExitThreadCore();
}
ExitThreadCore是做什么的?
好吧,它不会直接杀死线程,但会启动进程:
ExitThread 和 ExitThreadCore 实际上不会导致线程终止。这些方法引发 Application 对象侦听的 ThreadExit 事件。Application 对象然后终止线程。
然而,真正有趣的一点似乎发生在array[i].Dispose(disposing)
作为此方法的一部分,我们看到:
if (this.messageLoopCount > 0 && postQuit)
{
this.PostQuit();
}
PostQuit() 是发送WM_QUIT
消息的内容。所以我们也应该考虑什么时候Application.ThreadContext.Dispose
被调用,它似乎总是在表单关闭之后,尽管我很高兴在那里得到更正。
所以订单似乎是关闭所有表单,然后发送 WM_QUIT 消息。我认为你是对的,文档实际上可能有错误的顺序事件......
这也证实了我们经常看到的另一个副作用;当应用程序关闭但仍有线程在后台运行时,exe 仍将在正在运行的应用程序列表中。表单已经关闭,但仍然有流氓线程在阻止 Exit() 完成。
正如特吉弗所说:
线程要么是后台线程,要么是前台线程。后台线程与前台线程相同,只是后台线程不会阻止进程终止。一旦属于一个进程的所有前台线程都已终止,公共语言运行时就会结束该进程。任何剩余的后台线程都将停止并且不会完成。
(来自Thread.IsBackgroundThread)
我也想知道是什么Environment.Exit
:
[SecurityCritical, SuppressUnmanagedCodeSecurity]
[DllImport("QCall", CharSet = CharSet.Unicode)]
internal static extern void _Exit(int exitCode);
它有效地调用操作系统来终止进程;这将毫不费力地终止所有窗口;例如, OnFormClosing 可能永远不会触发。作为此批发终止的一部分,它还将[我犹豫使用尝试,因为我从未见过它失败] 杀死任何线程,包括消息循环正在运行的“主”线程。