我分叉了一个孩子,我正在尝试同步它们以便打印
child 0
parent 0
child 1
parent 1
我必须使用sigsuspend
,这是我目前的代码,我得到的只是parent suspend
。没有孩子的踪迹。
int c=0, receivedP=0, receivedC=0;
sigset_t setParent, setChild;
void handler(int s){
if(s==SIGUSR1){
receivedC=1;
printf("parent --sig1--> child\n");
c++;
}
else{
receivedP=1;
printf("child --sig2--> parent\n");
}
}
void child(){
sigfillset(&setChild);
sigdelset(&setChild,SIGUSR1);
sigdelset(&setChild,SIGINT); //this makes me able to terminate the program at any time
while(1){
if(receivedC==0){
printf("child suspend\n");
sigsuspend(&setChild);
}
receivedC=0;
printf("child %d\n",c);
kill(getppid(),SIGUSR2);
}
}
void parent(pid_t pf){
sigfillset(&setParent);
sigdelset(&setParent,SIGUSR2);
sigdelset(&setParent,SIGINT); //this makes me able to terminate the program at any time
kill(pf,SIGUSR1);
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
}
int main(){
signal(SIGUSR1,handler);
signal(SIGUSR2,handler);
pid_t p;
p= fork();
if(!p)child();
else parent(p);
return 0;
}
有人知道造成这种情况的原因是什么吗?
答案 0 :(得分:1)
我认为你对信号的一个经典问题感到茫然。
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
想象一下,如果来自孩子的信号在<{1}}和if(receivedP==0)
的指示之间,会发生什么。处理程序将执行,并将sigsuspend(&setParent)
设置为1,但主循环不会再次检查;它将进入receivedP
而永远不会出现。
为了安全地使用sigsuspend
,当程序不调用sigsuspend
时,您需要始终阻止您关心的信号。您可以使用sigsuspend
执行此操作。确保在执行处理程序期间阻止信号也是必要的,这需要您使用sigprocmask
代替sigaction
(但您应该这样做)无论如何,由于signal
严重不明确,系统到系统的变化会咬你的屁股。“
确保在signal
期间 仅传递信号后,您不再需要sigsuspend
和receivedP
个变量;你知道信号发生了,或receivedC
不会返回。 (如果你的程序在每个进程中都等待一个以上的信号,那就不是这样了,但是在这一点上事情会变得复杂得多;在它出现之前不要担心它。)
事实上,一旦你确定了,你就不需要在信号处理程序中做任何。您的计数器变量可以是sigsuspend
和parent
的本地变量。在信号处理程序中尽可能少做最好的事情; C标准的字母允许您几乎不做任何事情而不会冒未定义的行为风险,而POSIX只会打开它一点点。 (为您练习:将此程序更改为使用sigwaitinfo
,以便它根本不需要处理程序功能。)
您的程序修改对我来说可靠。我还纠正了其他一些样式问题和小错误:请注意child
和parent
中的循环以不同的顺序执行,child
中的错误检查,以及我是仅阻止main
和SIGUSR1
,因为应该允许其他几个信号终止该过程(SIGUSR2
,SIGTERM
,{{1} },SIGHUP
,...)并且您不想要维护列表。阻止程序安装处理程序的信号就足够了。
SIGQUIT
我建议您一直阅读GNU C Library Manual section on signal handling;它包含了一些有关安全使用信号的有用建议。