【问题标题】:Parent and child sync by signals trouble父母和孩子通过信号故障同步
【发布时间】:2013-04-18 07:08:47
【问题描述】:

所以,我的任务是以这种方式同步父母和他的 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;
}

【问题讨论】:

  • 你是不是故意写的 while (0 == flag_p) { }; ?
  • @AnishRam 不,孩子在父亲中获得的价值是孩子的 pid。
  • 'while (0 == flag_p) { };'阻止孩子,直到父母的信号被释放
  • 但是 flag_p 没有相互连接。每个进程都有自己的 flag_p
  • 这就是为什么我使用父母发送给孩子的信号 SIGUSR1 来更改 flag_p 值

标签: c linux synchronization signals


【解决方案1】:

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

while (flag_p == 0) { }

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

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

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

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

【讨论】:

  • 感谢您的回复。我不明白的是,当两个孩子同时向父母发送信号时。您确定该处理程序将执行一次吗?如果是这样,这个麻烦的解决方案是什么?
  • 实际上,我添加了 'volatile' 但它对我没有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 2020-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多