终止进程

终止进程的结果如下:

  • 进程中的任何剩余线程都标记为终止。
  • 将释放进程分配的任何资源。
  • 所有内核对象都已关闭。
  • 进程代码将从内存中删除。
  • 设置进程退出代码。
  • 进程对象已发出信号。

当进程终止时,内核对象的开放句柄会自动关闭,但对象本身就存在,直到关闭所有打开的句柄。 因此,如果另一个进程具有打开的句柄,则使用该对象的进程终止后,该对象将保持有效。

GetExitCodeProcess 函数返回进程的终止状态。 执行进程时,其终止状态为STILL_ACTIVE。 进程终止时,其终止状态从STILL_ACTIVE更改为进程的退出代码。

当进程终止时,进程对象的状态会发出信号,释放任何一直在等待进程终止的线程。 有关同步的详细信息,请参阅 同步多线程的执行

当系统终止进程时,它不会终止该进程创建的任何子进程。 终止进程不会为WH_CBT挂钩过程生成通知。

使用 SetProcessShutdownParameters 函数可以指定系统关闭时进程终止的某些方面,例如进程何时应相对于系统中的其他进程终止。

如何终止进程

进程将执行,直到发生以下事件之一:

  • 进程的任何线程都调用 ExitProcess 函数。 请注意,如果进程的主线程返回,C 运行时库的一些实现 (CRT) 调用 ExitProcess
  • 进程的最后一个线程终止。
  • 任何线程使用进程的句柄调用 TerminateProcess 函数。
  • 对于控制台进程,当控制台收到 Ctrl+C 或 CTRL+BREAK 信号时,默认控制台 控件处理程序 将调用 ExitProcess
  • 用户关闭系统或注销。

除非进程线程处于已知状态,否则不要终止进程。 如果线程正在等待内核对象,则在等待完成之前不会终止该线程。 这可能会导致应用程序停止响应。

主线程可以通过指示其他线程在导致进程终止 (之前调用 ExitThread 来避免终止其他线程,有关详细信息,请参阅 终止线程) 。 主线程在之后仍可调用 ExitProcess ,以确保所有线程都终止。

进程的退出代码是在调用 ExitProcessTerminateProcess 中指定的值,或者由进程的 main 或 WinMain 函数返回的值。 如果进程因致命异常而终止,则退出代码是导致终止的异常的值。 此外,此值用作发生异常时正在执行的所有线程的退出代码。

如果进程由 ExitProcess 终止,则系统会调用每个附加 DLL 的入口点函数,值指示进程正在与 DLL 分离。 当进程被 TerminateProcess 终止时,DLL 不会收到通知。 有关 DLL 的详细信息,请参阅 动态链接库

如果进程被 TerminateProcess 终止,则进程的所有线程将立即终止,没有机会运行其他代码。 这意味着线程不执行终止处理程序块中的代码。 此外,不会通知附加的 DLL 进程正在分离。 如果需要让一个进程终止另一个进程,以下步骤提供了更好的解决方案:

  • 让这两个进程调用 RegisterWindowMessage 函数来创建私人消息。

  • 一个进程可以通过使用 BroadcastSystemMessage 函数广播专用消息来终止另一个进程,如下所示:

     DWORD dwRecipients = BSM_APPLICATIONS;
        UINT uMessage = PM_MYMSG;
        WPARAM wParam = 0;
        LPARAM lParam = 0;
    
        BroadcastSystemMessage( 
            BSF_IGNORECURRENTTASK, // do not send message to this process
            &dwRecipients,         // broadcast only to applications
            uMessage,              // registered private message
            wParam,                // message-specific value
            lParam );              // message-specific value
    
  • 接收私人消息的进程调用 ExitProcess 以终止其执行。

ExitProcessExitThreadCreateThreadCreateRemoteThreadCreateProcess 函数的执行在地址空间内序列化。 存在以下限制:

  • 在进程启动和 DLL 初始化例程期间,可以创建新线程,但在进程完成 DLL 初始化之前,它们不会开始执行。
  • 一次只能有一个线程在 DLL 初始化或分离例程中。
  • 在 DLL 初始化或分离例程中没有线程之前, ExitProcess 函数不会返回。