0

所以,我的任务是以这种方式同步父母和他的 2 个孩子:一个孩子向父母发送 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;
}
4

1 回答 1

0

我的猜测是volatile一些全局变量声明中缺少它。例如,flag_p不是volatile意味着循环

while (flag_p == 0) { }

可以永远运行:GCC 可能编译它只将全局变量加载到一个寄存器中,然后循环直到这个寄存器非零(这永远不会发生)。

一个保守的近似是,您应该volatile在信号处理程序中读取或写入所有可变变量。

编辑:我能想到的另一个问题来源是信号不是累积的:父进程没有挂起的 SIGUSR2,或者它有一个。据我所知,如果两个子进程同时将其发送到父进程,则可能只会传递一个。

编辑:我认为一个“更好”的解决方案(更灵活,更便携)将遵循以下原则:根本不使用信号,而是使用管道。您在父母和每个孩子之间制作一个管道,孩子们在完成后通过管道发送一个字符“X”。父母等待 select(); 或者如果它只是想等到两个孩子都准备好,它可以从一个管道读取“X”字符,然后从另一个管道读取,在两种情况下都阻塞(顺序无关紧要)。

于 2013-04-18T13:08:30.640 回答