我不确定更复杂的信号和分叉问题。来自孩子或父母的信号呼叫之间有区别吗?
当孩子分叉时,它现在是父母而只是前一个父母的孩子吗?
由于包含处理程序,默认处理程序无效。那么您可以将SIGINT
更改为不终止进程吗?
int count = 0;
void killhandler(int sig){
printf("SIGKILL received\n");
return;
}
void childhandler(int sig){
int status;
wait(&status);
count += WEXITSTATUS(status);
return;
}
main(){
int i; // for loop iterator
pid_t pid[3]; // pids of child processes
Signal(SIGKILL, killhandler);
Signal(SIGCHLD, childhandler);
// Fork 3 child processes
for(i=0; i<3; i++){
pid[i] = fork();
if(!pid[i]){ // If child process
Signal(SIGKILL, SIG_DFL);
exit(5);
}
}
// Parent process only
for(i=0; i<3; i++){
kill(pid[i], SIGKILL);
}
sleep(5);
printf("count = %d\n", count);
exit(0);
}
为什么"SIGKILL received"
从未打印过?
为什么只计算:0,5,10,15
答案 0 :(得分:3)
来自孩子或父母的信号呼叫之间有区别吗?
就如何影响接收信号的过程而言,没有。
当孩子分叉时,它现在是父母而只是前一个父母的孩子吗?
它绝对是其父母的孩子。它是否成为父母本身取决于它是否要求自己的孩子。
由于包含处理程序,默认处理程序无效。那么你可以改变SIGINT以不终止进程吗?
SIGINT的默认处置是终止进程,但您可以捕获并处理SIGINT,也可以阻止或忽略它。
,默认处置与覆盖无关,直到(以及如果)再次更改为止为什么“SIGKILL收到”从未打印过?
您无法阻止,忽略或捕获SIGKILL。你不会看到你的处理程序打印任何东西,因为它永远不会被调用SIGKILL。 SIGSTOP同样不能被忽略,阻止或处理。在这方面,这是两个特殊信号。
在你的程序中,你试图将SIGKILL设置为默认值,实际上它只是 ,在子节点中处置。由于您的孩子立即退出,父母的信号可能永远不会被传递,因为孩子已经死了,父母的kill
可能会因ESRCH失败,例如没有那个带有那个pid的孩子了。 sleep
会有帮助,所以他们可以活得足够长,可以被杀死。 (一定要喜欢这个术语。)
您使用WEXITSTATUS
是错误的。如果你的意图是计算出自己的意志退出而不是被杀的孩子的数量,你可能只想要一个使用WIFEXITED或WIFSIGNALED的简单计数器。 WEXITSTATUS返回自己退出的子项的状态代码。它可能是0或1或50或75.将它添加到变量可能不是你想要的。
信号是一个令人困惑的主题,因为洋葱有几个层,并且规则和平台特定语义有足够的例外以使它们令人沮丧。我从来没有找到一个涵盖它们的单一来源。也就是说,信号配置和处理程序是洋葱的外层,网上有很多可用的资源,非常好。
答案 1 :(得分:2)
分叉子进程时,它非常接近父进程的精确副本。对于单线程进程,有三个主要区别:
fork()
的返回值不同(有关其他差异,请参阅fork()
的POSIX手册页。)子项中的信号处理程序与父项中的信号处理程序相同。但是,孩子当然可以独立地改变其任何信号处理程序。
您无法设置信号处理程序来捕获SIGKILL。这个信号永远不会被抓住。