在叉号调用之后,我有一个父亲必须向他的孩子发送sigusr1或sigusr2(基于'cod'变量的值)。在接受sigusr1或sigusr2之前,孩子必须安装适当的处理程序。为了这样做,我暂停父亲等待孩子发出信号告诉他已完成处理程序安装。父亲由sigusr1发出信号,并且在fork调用之前安装了此信号的处理程序。然而,看起来父亲不能从暂停中回来让我觉得他实际上从不打电话给sigusr1处理程序。
[...]
typedef enum{FALSE, TRUE} boolean;
boolean sigusr1setted = FALSE;
boolean sigusr2setted = FALSE;
void
sigusr1_handler0(int signo){
return;
}
void
sigusr1_handler(int signo){
sigusr1setted = TRUE;
}
void
sigusr2_handler(int signo){
sigusr2setted = TRUE;
}
int main(int argc, char *argv[]){
[...]
if(signal(SIGUSR1, sigusr1_handler0) == SIG_ERR){
perror("signal 0 error");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == 0){
if(signal(SIGUSR1, sigusr1_handler) == SIG_ERR){
perror("signal 1 error");
exit(EXIT_FAILURE);
}
if(signal(SIGUSR2, sigusr2_handler) == SIG_ERR){
perror("signal 2 error");
exit(EXIT_FAILURE);
}
kill(SIGUSR1, getppid()); // wake up parent by signaling him with sigusr1
// Wait for the parent to send the signals...
pause();
if(sigusr1setted){
if(execl("Prog1", "Prog1", (char*)0) < 0){
perror("exec P1 error");
exit(EXIT_FAILURE);
}
}
if(sigusr2setted){
if(execl("Prog2", "Prog2", (char*)0) < 0){
perror("exec P2 error");
exit(EXIT_FAILURE);
}
}
// Should'nt reach this point : something went wrong...
exit(EXIT_FAILURE);
}else if (pid > 0){
// The father must wake only after the child has done with the handlers installation
pause();
// Never reaches this point ...
if (cod == 1)
kill(SIGUSR1, pid);
else
kill(SIGUSR2, pid);
// Wait for the child to complete..
if(wait(NULL) == -1){
perror("wait 2 error");
exit(EXIT_FAILURE);
}
[...]
}else{
perror("fork 2 error");
exit(EXIT_FAILURE);
}
[...]
exit(EXIT_SUCCESS);
}
答案 0 :(得分:0)
从评论中汇总一个看似合理的答案 - 所以这是社区Wiki从一开始就是如此。 (如果奥利提供了答案,那么就投票而不是这个!)
Oli Charlesworth给出了问题的核心内容:
pause()
之前,孩子已将SIGUSR1发送给父母。ouah准确地注意到了:
volatile sig_atomic_t
类型,否则代码未定义。也就是说,POSIX允许比标准C更多的松弛,因为它可以在信号处理程序中完成。我们可能还会注意到C99提供了<stdbool.h>
来定义bool
类型。
原始海报评论说:
我不知道如何确保父母在
pause()
调用时不先在孩子中使用sleep()
(不保证任何内容)。有什么想法吗?
建议:使用usleep()
(μ-sleep,或以微秒为单位睡眠)或nanosleep()
(以纳秒为单位睡眠)?
或使用其他同步机制,例如:
open()
调用返回而被解除阻塞时,两个进程都只是关闭FIFO; 请注意,两个进程之间没有通过FIFO进行数据通信;代码只是依赖于内核来阻止进程,直到有一个读者和一个编写器,所以两个进程都准备好了。
另一种可能性是,父进程可以尝试if (siguser1setted == FALSE) pause();
来减少竞争条件的窗口。但是,它只会减少窗口;它不能保证不会发生竞争条件。也就是说,墨菲定律适用,信号可以在测试完成和pause()
执行的时间之间到达。
所有这些都表明信号不是一个非常好的IPC机制。它们可以用于IPC,但它们实际上很少用于同步。
顺便说一句,没有必要测试任何exec*()
函数族的返回值。如果系统调用返回,则失败。
提问者再次问道:
使用进程间共享的POSIX信号量不是更好吗?
信号量肯定是同步这两个进程的另一种有效机制。因为我当然必须查看信号量的手册页,而我记得如何在不看的情况下使用FIFO,我不确定我是否真的使用它们,但创建和删除FIFO有其自身的一组问题所以不清楚它是否“更好”(或“更糟糕”);只是不同。 FIFO为mkfifo()
,open()
,close()
,unlink()
与sem_open()
(或sem_init()
),sem_post()
,{{1}信号量可以{},sem_wait()
,也许sem_close()
(或sem_unlink()
)。您可能想要考虑使用sem_destroy()
注册“FIFO删除”或“信号量清除”功能,以确保在尽可能多的情况下销毁FIFO或信号量。但是,对于测试程序来说,这可能是OTT。