信号总是先被父进程捕获

Signal is always caught by parent process first

在 Solaris 11.3(system(3C) 的简化版本)下考虑以下代码 运行:

int main(int argc, char **argv) {

     pid_t pid = fork();
     pid_t w;
     int status;
     if (pid == 0) {
             execvp(argv[1], argv + 1);
             perror("Failed to exec");
             exit(127);
     }
     if (pid > 0) {
             w = waitpid(pid, &status, 0);
             if (w == -1) {
                     perror("Wait: ");
                     exit(1);
             }
             else if (WIFEXITED(status) > 0) {
                     printf("\nFinish code: %d\n", WEXITSTATUS(status));
             }
             else {
                     printf("\nUnexpected termination of child process.\n");
             }
     }
     if (pid == -1) {
             perror("Failed to fork");
     }

 }

我遇到的问题是,无论何时通过信号(例如,SIGINT)完成进程,都不会打印 "Unexpected termination" 消息。

在我看来,整个进程组都从终端接收信号,在这种情况下,父进程只是在 waitpid(2) returns 之前终止(显然每次都会发生)。

如果是这样的话,我有一个后续问题。如何在不使用信号处理程序的情况下从父进程检索有关终止子进程的信号的信息?例如,我可以添加另一个带有 WIFSIGNALED 检查的 if-else 块和传递变量 statusWTERMSIG 调用(事实上,我这样做了,但是在使用 Ctrl+C 终止时该程序没有提供任何输出)

那么那里到底发生了什么以及发生的顺序是什么?

如果你从另一个 tty 通过 "kill" 发送信号,它能正常工作吗?我在 linux 上试过这个。似乎是相同的行为。

如果 shell 控制信号被传递到过程组,我认为你是对的......并且你有一场比赛。您需要在 parent 中捕捉并延迟它们。

我所做的是做“./prog cat”

执行杀戮 -SIGINT 工作正常。

执行 control-C 不会打印任何内容。

在前面执行 setsid() parent 终止,但 child 保持 运行.

你说,“......每当进程通过信号完成时 (例如,SIGINT)......”,但你不够具体 使任何人都能明确地回答您的问题。 如果您使用 kill 命令向 child 进程发送信号, 你有一个奇怪的问题。 但是如果,正如我所怀疑的那样(并且正如你所说的那样 “整个过程组从终端接收信号”), 你只要输入Ctrl+C,很简单:

  • 当您键入 INTR、QUIT 或 SUSP 字符时, 发送相应的信号(SIGINT、SIGQUIT 或 SIGTSTP) 同时到终端进程组中的所有进程。
    • OK,严格来说,不是同时。 它发生在终端驱动程序的循环中 (具体来说,我相信,“行纪律”处理程序),在内核中。 在此循环完成之前,不能执行任何用户进程。
  • 你说“...... parent 进程简单地终止 在 waitpid(2) returns 之前(……每次,apparently)。” 从技术上讲这是真的。 如上所述,进程组中的所有进程 (包括您的 parent 和 child 进程)接收信号 (基本上)同时。 由于 parent 本身不处理信号, 它在可能进行任何处理之前终止 由 child 收到信号触发。
  • 你说“信号总是首先被parent进程捕获”。 不;往上看。 进程以未指定的顺序终止—— 这可能是它们在流程中出现的顺序 table (这是不确定的), 或由一些微妙的(也许是未记录的)方面决定 调度程序的算法。

相关的 U&L 问题: