为什么不应该使用Process.GetCurrentProcess().Kill()来退出WinForm应用程序?

24

现在,当用户想要退出我的应用程序时,我会完成必要的一些工作(例如断开与服务器的连接,保存用户数据...),然后执行以下操作:

  • 使用布尔变量退出所有的主循环
  • 终止仍在运行的线程(通常是我的服务器轮询线程)
  • 友好地调用Application.Exit();

这需要几秒钟的时间才能退出,并且没有任何实际目的(因为所有内容都已经保存在服务器上,所以我不太关心那里发生了什么)。

如果我改为使用以下方式,则可以立即终止而无需考虑任何问题:

 System.Diagnostics.Process.GetCurrentProcess().Kill();

为什么我不直接终止进程,让CLR释放AppDomain呢?

我知道认真地处理共享资源(IO文件处理程序等)很重要(所以请不要回答这个问题:)),但是一旦完成后,是否有真正的理由来清洁退出我的应用程序?


1
我猜测在这种情况下任何finally块都不会被处理,这可能会导致未来其他人维护代码时出现意外的错误。 - Hosam Aly
@Hosam:这是一个很好的观点。为什么不把它发布为答案,以便可以得到赞同? - Brann
7个回答

12
杀死进程意味着 finally 块将不会被执行,甚至可能连关键的终结对象也不会被执行,这些对象可能实际上是关键的,会导致系统级别的资源泄漏。它还可能在未来引起意外的 bug,当其他人维护代码时,他们(或您)必须费尽心思地考虑每次编写 finally 块时是否会被执行。

操作系统不应该因为一个进程被终止就泄露资源。但是finally块和finalizer是一个不错的观点。 - Qwertie
1
@Qwertie 是的,但有时确实会发生这种情况。例如,即使应用程序崩溃,相机可能仍然保持打开状态。这可能是驱动程序中的错误,但也是“系统”的一部分。 - Hosam Aly

4
首先,我认为你指的是Process.Kill()而不是Process.TerminateProcess()。其次,杀死进程只会强制结束它。任何清理代码都不会执行,你的应用程序也没有机会取消杀死进程(例如,如果用户有未保存的数据)。如果你对此满意,就这么做吧。

1
实际上是 Process.GetCurrentProcess().Kill(); 我已经相应地修复了我的帖子。感谢您注意到它! :) - Brann

4

这确实是个好问题!

十多年前,我写了一个VB6应用程序,由于与一个特定的证书通信的Web服务器上确认的WinINet OCX(或者它被称为什么)中的错误导致其在终止时挂起。

由于没有任何方法来解决这个错误,我使用了TerminateProcess,据我所知,这个应用程序在数千台机器上使用了几年,我从未听说过任何关于这个黑客的问题!


我现在有一个测试用例,使用Kill hack会失败。这是因为它是掷骰子式的,准确地说是进程何时被杀死、进程正在执行什么操作以及应该发生什么。这就是为什么ACID数据库要付出巨大的努力来确保数据写入/可重放性-这样它们可以随时粗暴地关闭而不会丢失数据。如果卡住的进程没有处理关键数据(当时或以后),那么请毁掉它;这与通过进程资源管理器终止进程没有什么区别。 - user2864740

1

需要注意的是,终结器可能永远不会被执行, 因此杀死进程与跳过终结器代码的任何其他原因(例如慢终结器或终结器抛出异常)并没有太大区别。

总的来说,如果应用程序关闭需要几秒钟时间,特别是如果它立即隐藏所有窗口并且对用户“消失”,那么我不会太担心。然而,如果关闭需要数十秒钟和/或用户可能会再次执行该应用程序并且它不支持多个实例,则调用Process.Kill可能是一个好主意。

我知道一些应用程序需要很长时间才能终止,我希望有一天它们可以残忍地自杀,而不是让我作为用户去做这件事(在操作系统重新启动时尤其令人恼火)。


1

当使用第三方库没有办法捕获它们的错误或泄漏时,有时唯一的结束方式是杀死进程,而不是弹出崩溃消息框。


1
请记住,如果您正在写入文件/网络流,则可能会出现写入不完整的情况。
如果您的应用程序已准备好以这种方式处理损坏的数据,则没有理由不这样做。但是,如果您可以通过其他方式退出,我建议这样做。

0
为什么不使用System.Environment.Exit(int)?这似乎是为了节省代码而做的。对我来说,更清晰的方法是看到Exit调用所做的事情,你的关闭将更受控制,Finalizers和Critical Finalizers将运行。

Environment.Exit(int) 不能保证在底层应用程序域或本地代码跳转到 WER / ReportFault 函数族时退出。即使使用 Kill() 也不能保证终止,因为内核级死锁会阻止进程退出,但 Kill 通常会立即终止,而 Exit 允许程序进行清理。 - Петър Петров

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接