没有儿童过程的痕迹

时间:2016-11-01 14:06:24

标签: c process signals fork child-process

我分叉了一个孩子,我正在尝试同步它们以便打印

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;
}

有人知道造成这种情况的原因是什么吗?

1 个答案:

答案 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期间 传递信号后,您不再需要sigsuspendreceivedP个变量;你知道信号发生了,或receivedC不会返回。 (如果你的程序在每个进程中都等待一个以上的信号,那就不是这样了,但是在这一点上事情会变得复杂得多;在它出现之前不要担心它。)

事实上,一旦你确定了,你就不需要在信号处理程序中做任何。您的计数器变量可以是sigsuspendparent的本地变量。在信号处理程序中尽可能少做最好的事情; C标准的字母允许您几乎不做任何事情而不会冒未定义的行为风险,而POSIX只会打开它一点点。 (为您练习:将此程序更改为使用sigwaitinfo,以便它根本不需要处理程序功能。)

您的程序修改对我来说可靠。我还纠正了其他一些样式问题和小错误:请注意childparent中的循环以不同的顺序执行,child中的错误检查,以及我是阻止mainSIGUSR1,因为应该允许其他几个信号终止该过程(SIGUSR2SIGTERM,{{1} },SIGHUP,...)并且您不想要维护列表。阻止程序安装处理程序的信号就足够了。

SIGQUIT

我建议您一直阅读GNU C Library Manual section on signal handling;它包含了一些有关安全使用信号的有用建议。