忽略父进程中的信号

时间:2015-09-22 03:55:51

标签: c signals

我正在尝试实现一个shell程序,我希望shell程序忽略SIG_INT(ctrl + c)。但是在我的程序中,孩子也忽略了SIG_INT信号,因为exec应该将子进程带到另一个程序,并且该程序应该默认处理SIG_INT信号。我应该怎么做才能在按下ctrl + c时终止子进程。

新编辑:在我的子进程块中放置信号(Certain_signal,SIG_DFL)后,我的代码运行正常。但我仍然对这项工作的方式感到困惑。这是否意味着信号和信号处理都可以通过执行命令传播?

int main(void){
signal(SIG_INT, SIG_IGN);
int result = fork();
if(result == 0){
    //child:
    //exec some programs
}
else{
    waitpid(result);
    //do something
}

}

1 个答案:

答案 0 :(得分:7)

我相信你已经误解了exec如何修改信号处理。在Linux exec手册页中,例如(1),它表明(我的重点):

  

execve()期间保留所有流程属性,但以下内容除外:

     
      
  • 捕获 的任何信号的处置都会重置为默认值(signal(7))。

  •   
  • <在此问题的背景下,很多其他不相关的内容>

  •   

正被捕获的信号与被忽略的信号相同,如signal手册页所示:

  

使用这些系统调用,进程可以选择在传递信号时发生以下行为之一:

     
      
  • 执行默认操作;
  •   
  • 忽略信号;或
  •   
  • 使用信号处理程序捕获信号,这是一个程序员定义的函数,在信号传递时自动调用。
  •   

这实际上是有道理的,因为虽然忽略信号可以通过exec调用传播,但是信号处理程序不能 - 用于处理信号的函数已被exec调用替换,所以试图称之为很可能是灾难性的。

你可以看到继承"忽略"通过编译以下两个程序qqp.c

进行处置
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

int main (void) {
    signal (SIGINT, SIG_IGN);
    puts("Parent start");
    if (fork() == 0)
        execl ("./qqc", 0);
    wait(0);
    sleep (1);
    puts("Parent end");
    return 0;
}

qqc.c

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int main (void) {
    //signal (SIGINT, SIG_DFL);
    puts("Child start");
    sleep (60);
    puts("Child end");
    return 0;
}

请注意,您还可以在forkexec之间更改第一个代码示例中的处置方式。如果您实际上并未控制第二个代码示例将执行的操作(例如,如果您正在调用您未编译的可执行文件),那么这将是首选。

运行qqp,无论您按 CTRL-C 多少次,父母和孩子都不会提前退出。但是,取消注释恢复默认行为的行,您可以轻松地突破孩子。

因此,如果您希望您的孩子恢复默认行为,您需要在孩子本身中执行此操作,例如:

signal (SIG_INT, SIG_DFL);

(1) POSIX has a little more detail关于会发生什么:

  

设置为调用过程映像中默认操作(SIG_DFL)的信号应设置为新过程映像中的默认操作。 除了SIGCHLD之外,调用过程映像设置为忽略(SIG_IGN)的信号应设置为被新过程映像忽略。设置为被捕获的信号调用过程映像应设置为新过程映像中的默认操作(请参阅<signal.h>)。如果调用过程映像将SIGCHLD信号设置为忽略,则未指定SIGCHLD信号是设置为忽略还是新过程映像中的默认操作。

而且,只是在您的编辑中我提出的解决方案有效,但它为您提出了另一个问题:

  

这是否意味着信号和信号处理都可以通过执行命令传播?

信号本身不会通过exec呼叫传播,信号实际上是&#34;中断&#34;正在生成。这与信号处理程序(处理信号的代码)或信号处理(信号发生时该怎么做)有所不同。如上所示,处置可以在exec调用之后存在,但处理程序不能。信号也没有。

当您按 CTRL-C 并且多个进程受到影响时您所看到的内容与在exec边界上继承信号无关,它还有更多信息与终端的东西有关。

传递给单个进程的信号不会影响其任何子进程。但是,按 CTRL-C 向单个进程发送信号。 POSIX终端接口具有控制终端和进程组的概念:

  

每个流程也是流程组的成员。每个终端设备记录一个称为其前台进程组的进程组。进程组控制终端访问和信号传递。 终端生成的信号将发送给作为终端前台进程组成员的所有进程。