在TerminateProcess(GetCurrentProcess(),exit_code)之后需要等待吗?

时间:2016-11-04 16:13:18

标签: windows win32-process

TerminateProcess的文档部分说明:

This function stops execution of all threads within the process and requests
cancellation of all pending I/O.

...

TerminateProcess is asynchronous; it initiates termination and returns
immediately. If you need to be sure the process has terminated, call the
WaitForSingleObject function with a handle to the process.

如果你使用TerminateProcess来提交进程自杀,会留下一些含糊不清的地方,如:

TerminateProcess(GetCurrentProcess(), exit_code)

从逻辑上讲,这应该足够了,但文档之后执行可能会继续,如果你因为一个让你的进程处于不确定状态的错误而调用TerminateProcess会很危险。

我发现最接近确认不需要等待自杀的是_invoke_watson的源代码:

C:\Program Files (x86)\Windows Kits\10\Source\10.0.10240.0\ucrt\misc\invalid_parameter.cpp

这个函数最后做的就是自己调用TerminateProcess - 没有等待。

获得确定性会很好,我想在这里提出这个问题,以便答案可以作为文档的补充。

1 个答案:

答案 0 :(得分:1)

我从离线的人那里得到了这个答案,他们不愿意在这里发布:

我对用户模式文档的看法是,TerminateProcess通常是一个进程对另一个进程执行的操作,并且文档是为了这种通用性编写的,从这个意义上来说是正确和合理的。

给TerminateProcess一个其他进程的句柄,你当然希望这个电话回复给你继续操作。

文档指出的是,呼叫的成功并不意味着其他进程已经终止,只是它的终止已经成功开始。

如果你不仅仅依赖于此,那么你肯定会做错事。因此,研究究竟什么是可靠的,甚至是考虑它,对我来说似乎从来没有用过。尽管我已经烦恼了,但我还是认为,当TerminateProcess返回给你时,另一个进程及其所有线程都被标记为已终止 - 字面意思是,它们设置了Terminated位。 ETHREAD - 但继续执行APC,通常用于完成或取消I / O等操作。虽然这种持续执行受到很大限制,但可能需要一些无限期的时间。因此,如果您需要知道所有执行都已完成,那么您需要注意要发出信号的过程。

当然,调用TerminateProcess来终止另一个进程是一件很残酷的事情,文档也提到了这一点。

相同过程

调用TerminateProcess来终止你自己的进程同样是残酷的。除了一个例外,它是最后的手段,即使在这种背景下,也是一个非常绝望的手段。任何执行此操作的人都必须遇到比调用可能返回的问题更大的问题,否则他们肯定会调用ExitProcess,它显然不会返回(但可能会使进程陷入死锁)。

通过TerminateProcess自终止引入了一个被终止的线程之一是当前线程的情况。终止后的APC处理没有为它激活:在Windows 7内核中,请参阅PspTerminateThreadByPointer,这再次使得当前线程的用户模式终止转到非返回的PspExitThread而不是为APC排队的特殊情况。最后退出。

所以,我的读法是带有-1作为句柄的TerminateProcess不返回,但是如果你在内核中执行最后一个为调用线程执行的指令,你可以看到你的进程中的其他线程可能仍然执行处理APC,但你的APC队列耗尽,即将被切断,永远不会回来。实际上,如果此时您的线程以某种方式处理APC,则内核错误检查!

顺便说一下,TerminateProcess的例外是残酷的,它本质上是NTDLL做的最后一件事,即使是通过ExitProcess进行相对温和的自我终止。它肯定是众所周知的,但总是让我感到惊讶的是,处理RtlExitUserProcess,NTDLL调用NtTerminateProcess 两次。首先,进行用户模式清理并调用NtTerminateProcess,将NULL作为句柄。如果成功,那么还有更多的用户模式清理,最后调用NtTerminateProcess,给出-1作为句柄。

好吧,最后一次调用就是你从TerminateProcess获得的,带有-1作为句柄。当您通过TerminateProcess自行终止时,您只是在用户模式和内核模式下跳过了您从ExitProcess获得的清理。无论如何,当TerminateProcess实际上是由NTDLL作为ExitProcess的结束时,它显然不会返回。