【问题标题】:Windows console signal handling for subprocess c++子进程 C++ 的 Windows 控制台信号处理
【发布时间】:2019-06-19 03:16:13
【问题描述】:

假设我们有一个用 C++ 编写的小程序,如下所示。
该程序本身有意不通过 WinAPI 调用 SetConsoleCtrlHandler 执行信号处理 - 这是问题的重要部分。

#include <stdio.h>
#include <stdlib.h>

int main() {
  while(true) {
    int status = system("EXTERNAL COMMAND");
    printf("RESULT STATUS = %d\n", status);
  }
}

当在终端中按下Ctrl+C 组合键时,上述程序的行为完全不同,具体取决于调用了哪个"EXTERNAL COMMAND"

1) 如果外部命令为pause,程序将陷入无限循环,逐步调用pause命令,并打印"RESULT STATUS = 0" many times,而不是通过进程kill强制终止。
2) 如果choice 中有外部命令,程序将在Ctrl+C 压力后立即终止。它不会打印任何内容,也不会从system 调用返回。
3) 如果外部命令是set /P VAR=,程序有很多有趣的行为。当按下Ctrl+C 时,程序会打印“RESULT STATUS = 1”并继续工作,直到执行第一次异步调用。

第一种和第二种情况可以用以下方式解释。终端窗口位于用户输入和目标程序之间,因此当用户按下Ctrl+C 时,终端窗口会自行向目标进程执行调度信号。
因此,一些子进程可以通过hConsole = GetStdHandle(STD_OUTPUT_HANDLE) 手动获取终端处理程序并执行自己的信号处理。另一个子进程不这样做,因此将信号传递给父进程并终止它。

但是第三种情况会引起很大的问题。如果子进程拦截SIGINT,为什么父进程在第一次异步调用后执行终止。如果不是,为什么它不立即终止,为什么以及如何打印“RESULT STATUS = 1”并继续工作。

谢谢

【问题讨论】:

  • @eryksun 谢谢!答案的关键是create a new thread in each attached process - 在这种情况下,很清楚进程终止如何以异步方式执行。

标签: c++ windows cmd signals windows-console


【解决方案1】:

Windows 中没有 Unix 信号,至少内核没有。也就是说,Windows 和 Windows API 基本上基于 C 编程语言,它是与 Unix 一起开发的,确实需要six signals。 Windows 中的 C 运行时在进程内模拟 SIGABRTSIGTERM(例如,与 C raise 一起使用)。对于SIGSEGVSIGILLSIGFPE,它使用操作系统异常处理程序。在控制台应用程序中,标准SIGINT 和非标准SIGBREAK 与C 运行时的控制台控制处理程序相关联,该处理程序通常是通过SetConsoleCtrlHandler 注册的第一个处理程序。 CTRL_C_EVENT 映射到SIGINT 信号处理程序,所有其他(CTRL_BREAK_EVENTCTRL_CLOSE_EVENT)都映射到SIGBREAK 处理程序。

控制台控制事件由控制台主机 (conhost.exe) 发送,它通过让会话服务器 (csrss.exe) 在客户端进程中创建线程来实现这一点。该线程从 kernelbase.dll 中未记录的 CtrlRoutine 函数开始,该函数遍历已注册的控制处理程序,直到其中一个通过返回 true 来处理事件。如果它们都不处理事件,则默认处理程序调用ExitProcess(STATUS_CONTROL_C_EXIT)。请注意,SetConsoleCtrlHandler(NULL, TRUE) 设置了一个标志,使CtrlRoutine 忽略CTRL_C_EVENT,并且此标志由子进程继承,并在使用标志CREATE_NEW_PROCESS_GROUP 创建进程时默认启用。此外,对于CTRL_CLOSE_EVENT,会话服务器给每个进程 5 秒的时间来处理事件并自行退出,否则它会强制终止进程。

要了解 CMD 的内部 PAUSE 命令发生了什么,请参阅 SetConsoleMode,尤其是 ENABLE_PROCESSED_INPUTPAUSE 调用 C _getch,它临时将控制台输入模式设置为 0。在禁用已处理输入模式的情况下,Ctrl+C 被简单地读取为“\x03”,而不是生成 CTRL_C_EVENT

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多