所以,我的任务是以这种方式同步父母和他的两个孩子: 一个孩子向父母发送SIGUSR2信号,然后阻止等待父母的信息。 同步由全局标志实现,因此父等待任何flag_ch变为1(它发生在子节点发送SIGUSR2时),然后向该子节点发送信号SIGUSR1,并且子节点恢复(导致全局flag_p变为1)
问题是父母只接收来自一个孩子的信号,然后阻止等待第二个孩子的信号,但它们没有出现 。 任何想法?..#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/signalfd.h>
#define LPC 10
pid_t ch[2];
sig_atomic_t flag_ch[2] = {0, 0};
sig_atomic_t flag_p = 0;
int get_ind(pid_t ch_pid) {
int i;
for (i = 0; i < 2; ++i) {
if (ch_pid == ch[i])
return i;
}
return -1;
}
void usr_handler(int signo, siginfo_t* si, void* unused) {
int ch_index;
switch(signo) {
case SIGUSR2:
ch_index = get_ind(si->si_pid);
if (ch_index >= 0)
flag_ch[ch_index] = 1;
else
fprintf(stderr, "signal handled not from child pid %d\n", si->si_pid);
break;
case SIGUSR1:
flag_p = 1;
break;
}
}
void set_usr_handler(void) {
struct sigaction sa;
sa.sa_sigaction = usr_handler;
sa.sa_flags = SA_SIGINFO;
sa.sa_restorer = NULL;
sigemptyset(&sa.sa_mask);
if (0 != sigaction(SIGUSR1, &sa, NULL))
abort_prg("signal [SIGUSR1] error");
if (0 != sigaction(SIGUSR2, &sa, NULL))
abort_prg("signal [SIGUSR2] error");
}
void child_proc(void) {
int i;
for (i = 0; i < LPC; ++i) {
if (0 != kill(getppid(), SIGUSR2))
exit(1);
while (0 == flag_p) { };
flag_p = 0;
}
}
int wait_child(void) {
while (0 == flag_ch[0] && 0 == flag_ch[1]) { };
if (1 == flag_ch[0]) {
flag_ch[0] = 0;
return ch[0];
}
flag_ch[1] = 0;
return ch[1];
}
void parent_proc(void) {
int i;
pid_t ch_pid;
for (i = 0; i < LPC * 2; ++i) {
ch_pid = wait_child();
printf("Parent: Received from pid [%d]\n", ch_pid);
if (0 != kill(ch_pid, SIGUSR1))
exit(1);
}
}
int main(int argc, char* argv[]) {
set_usr_handler();
int i;
for (i = 0; i < 2; ++i) {
pid_t child = fork();
if (0 > child)
exit(1);
if (0 == child) {
child_proc();
return 0;
}
ch[i] = child;
}
parent_proc();
return 0;
}
答案 0 :(得分:0)
我的猜测是它在一些全局变量声明中缺少volatile
。例如,flag_p
不是volatile
表示循环
while (flag_p == 0) { }
可以永远运行:GCC可能编译它只将一个全局变量加载到寄存器中,然后循环直到该寄存器非零(从不发生)。
保守的近似是你应该volatile
在信号处理程序中读取或写入的所有可变变量。
编辑:我能想到的另一个问题来源是信号不是累积的:父进程没有SIGUSR2挂起,或者它有一个。如果两个孩子同时将它发送到父进程,据我所知,只有一个可能会被传递。
编辑:我认为“更好”的解决方案(更灵活,更便携)将是:不要使用信号,而是使用管道。在父项和每个子项之间创建一个管道,子项在完成后在管道上发送一个字符“X”。父母等待select();或者如果它只是想等到两个孩子都准备好了,它可以从一个管道中读取'X'字符然后在另一个管道中读取,在两种情况下都会阻塞(顺序无关紧要)。