TerminateProcess vs Ctrl + C.

时间:2009-07-24 17:02:03

标签: windows console signals

我有一个控制台模式程序,它使用SQLite3来维护数据库文件。执行需要一段时间,但假设数据库写入发生,它应该在任何时候都是安全的取消。 (这都是在Windows下)

从运行程序的角度来看,在控制台中点击 Ctrl C 比让另一个程序调用TerminateProcess更安全吗?

我注意到如果调用TerminateProcess,我可以获得数据库损坏 - 我认为这是因为程序没有机会完成写入。我的猜测是 Ctrl C 更好,因为程序得到一个信号并自行终止,而不是操作系统将其终止。

请注意,程序实际上并不处理信号(除非SQLite这样做);我在谈论Win32可执行文件的内置默认机制来处理 Ctrl C 信号。

澄清/简化问题 - 鉴于此写作刚刚执行:

fwrite(buf, 1024*1024, 1, stream);

在此写入过程中,TerminateProcess的行为是否与 Ctrl C 不同?

4 个答案:

答案 0 :(得分:5)

所有这些都是令人信服的论据,但唯一可以确定的方法是尝试它。所以我编写了一个简单的程序,分配1GB缓冲区,为其分配一些数据,然后使用单个fwrite()将其写入文件。我尝试了几种方法来使写入“损坏”数据(我特别期待截断文件):

  • 调用TerminateProcess(通过perl的kill函数和Win32 :: Process :: Kill)
  • 点击 Ctrl C
  • 使用任务管理器的“结束流程”
  • 使用Process Explorer的“Kill Process”

在每种情况下,没有什么能阻止写入,文件大小正确并且具有正确的数据。虽然“杀戮”会立即发生,但这个过程会持续到写完为止。

从I / O的角度看,TerminateProcess和 Ctrl C 之间没有区别 - 一旦写入开始,它似乎保证完成(禁止停电)。

答案 1 :(得分:1)

您的应用程序必须有机会处理 Ctrl C Ctrl Break ,作为击键或信号(取决于配置),这意味着应用程序有机会进行干净的退出,这将是一种更柔和的方式来终止进程,如果没有别的话,允许它多一点执行时间。

TerminateProcess更像是一个蠢货,应用程序无法处理它,它来自内核,如果应用程序可以处理它,这会产生各种问题,“un killable”进程挂起它们的TerminateProcess处理程序并拒绝退出。

据我所知,只要在进程上调用TerminateProcess,它就不能执行任何代码,没有清理,没有关闭,它刚刚结束,你无法处理它,它根本就没有意义你可以,而不是从安全角度来看。

关于处理Windows控制台信号的优秀代码项目文章:

http://www.codeproject.com/KB/winsdk/console_event_handling.aspx

实现上面的一些信号处理,你可以确保数据库写入有机会在程序退出之前完成,而不是让它有机会。

你可以阻止TerminateProcess,但它的'不是'礼貌'编程,它更像是root kit编程,我在rootkit.com上看过一篇很好的文章,所以一旦你拥有了无敌,就在那里搜索'Process Invincibility'过程中,它可以在收到这样的“请求”之后自己关闭,并在hnad之前执行任何清理,但这肯定是一个黑客攻击。

在我看来,您目前看到的 Ctrl C 行为是因为它没有立即结束正在运行的进程。

答案 2 :(得分:0)

即使在电源故障期间,SQLite声称是原子的,请参阅http://www.sqlite.org/atomiccommit.html

唯一的例外是某些磁盘系统会在数据实际写入磁盘盘片之前报告写入成功发生,即数据位于磁盘缓存中,或者操作系统位于SQLite中。请参阅http://www.sqlite.org/lockingv3.html部分6.0如何损坏数据库文件。

终止must stop all running threads and complete pending I/O operations before they exit的流程。如果流程没有崩溃,则应确保数据完整性。

答案 3 :(得分:0)

我相信为了您的目的,使用 Ctrl C 会更安全。这将导致发送到程序的信号终止。如果程序没有处理信号,它将在现场终止。

TerminateProcess强制终止进程和任何子线程。

来自MSDN

  

TerminateProcess函数终止   指定的进程及其所有   线程。 ......备注

     

使用TerminateProcess函数   无条件地导致进程   出口。全球数据的状态   由动态链接库维护   (DLL)可能会受到损害   使用TerminateProcess而不是   了ExitProcess。

     

TerminateProcess启动终止   并立即返回。这停止了   执行内部的所有线程   处理和请求取消   所有待处理的I / O.终止了   进程无法退出,直到所有挂起   I / O已完成或取消。

     

一个过程无法阻止自己   被终止。

有一些进程阻止TerminateProcess的方法,但我怀疑SQLite3会这样做。