我正在尝试实现一个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
}
Run Code Online (Sandbox Code Playgroud)
}
我相信你已经误解了如何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;
}
Run Code Online (Sandbox Code Playgroud)
并且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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,您还可以更改第一个代码示例中的处置,在fork和之间exec.如果您实际上没有控制第二个代码示例将执行的操作(例如,如果您正在调用未编译的可执行文件),那么这将是更可取的.
跑步qqp,无论您按压多少次,父母和孩子都不会过早退出CTRL-C.但是,取消注释恢复默认行为的行,您可以轻松地突破孩子.
因此,如果您希望您的孩子恢复默认行为,您需要在孩子本身中执行此操作,例如:
signal (SIG_INT, SIG_DFL);
Run Code Online (Sandbox Code Playgroud)
(1) POSIX有更详细的内容:
设置为
SIG_DFL调用过程映像中默认操作()的信号应设置为新过程映像中的默认操作.除此之外SIGCHLD,SIG_IGN调用过程映像设置为忽略()的信号应设置为被新过程映像忽略.设置为由调用过程映像捕获的信号应设置为新过程映像中的默认操作(请参阅参考资料<signal.h>).如果SIGCHLD调用过程映像将信号设置为忽略,则不指定SIGCHLD信号是设置为忽略还是设置为新过程映像中的默认操作.
而且,只是在您的编辑中我提出的解决方案有效,但它会为您提出另一个问题:
这是否意味着信号和信号处理都可以通过执行命令传播?
信号本身不会通过exec调用传播,信号实际上是生成的"中断".这与信号处理程序(处理信号的代码)或信号处理(信号发生时该怎么做)不同.如上所示,处置可以在exec通话中存活但处理程序不能.信号也没有.
当你按下CTRL-C并且多个进程受到影响时你所看到的与通过exec边界继承信号无关,它更多地与终端的东西有关.
传递给单个进程的信号不会影响其任何子进程.不过,按下CTRL-C并不能将信号发送到一个单独的进程.POSIX终端接口具有控制终端和进程组的概念:
每个流程也是流程组的成员.每个终端设备记录一个称为其前台进程组的进程组.进程组控制终端访问和信号传递.在终端处生成的信号被发送到作为终端的前台进程组的成员的所有进程.