Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 忽略父进程中的信号_C_Signals - Fatal编程技术网

C 忽略父进程中的信号

C 忽略父进程中的信号,c,signals,C,Signals,我正在尝试实现一个shell程序,我希望shell程序忽略SIG_INT(ctrl+c)。但在我的程序中,子进程也会忽略SIG_INT信号,这是不应该的,因为exec应该将子进程带到另一个程序,并且默认情况下该程序应该处理SIG_INT信号。我应该怎样做才能在按下ctrl+c时终止子进程 新编辑:在我将信号(某些信号,SIG_-DFL)放入我的子进程块后,我的代码工作正常。但我仍然不明白这是怎么回事。这是否意味着信号和信号处理都可以通过execute命令传播 int main(void){ si

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

新编辑:在我将信号(某些信号,SIG_-DFL)放入我的子进程块后,我的代码工作正常。但我仍然不明白这是怎么回事。这是否意味着信号和信号处理都可以通过execute命令传播

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

}

我相信您稍微误解了
exec
如何修改信号处理。在Linux
exec
手册页中,例如(1),它指出(我的重点):

在执行
execve()
期间,将保留所有流程属性,但以下属性除外:

  • 正在捕获的任何信号的处理将重置为默认值(
    信号(7)

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

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

  • 执行默认操作
  • 忽略该信号;或
  • 用信号处理程序捕捉信号,这是一种程序员定义的函数,在信号传递时自动调用
这实际上是有道理的,因为忽略一个信号可以通过
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;
}
#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;
}
注意,您还可以在第一个代码示例中更改
fork
exec
之间的配置。如果您不能实际控制第二个代码示例将执行的操作(例如,如果您正在调用一个未编译的可执行文件),则最好使用这种方法

运行
qqp
,无论您按CTRL-C键多少次,父对象和子对象都不会过早退出。但是,取消对恢复为默认行为的行的注释,您可以轻松脱离子对象

因此,如果您希望您的孩子恢复到默认行为,您需要在孩子身上执行以下操作:

signal (SIG_INT, SIG_DFL);

(1) 关于发生了什么:

在调用过程映像中设置为默认操作(
SIG_DFL
)的信号应设置为新过程映像中的默认操作
SIGCHLD
外,被调用进程映像设置为忽略的信号(
SIG\u IGN
)应被设置为被新进程映像忽略。
被调用进程映像捕获的信号应被设置为新进程映像中的默认动作(请参见
)。如果调用进程映像将
SIGCHLD
信号设置为忽略,则未指定是将
SIGCHLD
信号设置为忽略还是新进程映像中的默认操作


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

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

int main(void){
signal(SIG_INT, SIG_IGN);
int result = fork();
if(result == 0){
    //child:
    //exec some programs
}
else{
    waitpid(result);
    //do something
}
信号本身不会通过
exec
调用传播,信号实际上就是正在生成的“中断”。这与信号处理程序(处理信号的代码)或信号处理(信号发生时的操作)不同。如上所示,部署可能会在
exec
调用中幸存,但处理程序不能。信号也不一样

当您按下CTRL-C并影响多个进程时,您看到的与跨
exec
边界继承信号无关,更多的是与终端内容有关

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

每个流程也是流程组的成员。每个终端设备记录一个进程组,该进程组称为其前台进程组。过程组控制终端访问和信号传输终端生成的信号被发送到终端前台进程组的所有进程。


您是否尝试移动代码“信号(SIG_INT,SIG_IGN);”到“waitpid”部分之前的位置?我没有,但除非执行部分出错,否则这不应该是问题,对吗?但是如果我传递程序/bin/ls以执行函数,我的子进程的代码应该被丢弃并替换为/bin/ls程序的代码,对吗?然后写在/bin/ls程序中的处理程序应该在那里处理来自终端的中断(信号)。我对execv的想法还是错的吗?顺便说一句,我在代码中使用了execv,而不是execve,@lplouis,在最后一点上,它们最终都调用了相同的最终函数,所以这并不重要。如果执行ls,是的,所有处理程序要么成为SIG\u DFL,要么成为SIG\u IGN,但请记住这些不是处理程序。处理程序是在传递的信号上运行的代码。通过exec替换代码,处理程序不再有意义,这就是它们被重置的原因。然而,SIG_DFL和SIG_IGN可以在exec中存活下来,因为它们不涉及处理程序。对于
ls
,除非它将
SIGINT
重置为
SIG_-DFL