Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 父和子同步信号故障_C_Linux_Synchronization_Signals - Fatal编程技术网

C 父和子同步信号故障

C 父和子同步信号故障,c,linux,synchronization,signals,C,Linux,Synchronization,Signals,所以,我的任务是以这种方式同步父母和他的两个孩子: 一个子系统向父系统发送SIGUSR2信号,然后阻塞等待的父系统消息。 同步由全局标志实现,因此父级等待任何标志变为1(在子级发送SIGUSR2时发生),然后向该子级发送信号SIGUSR1,子级恢复(导致全局标志变为1) 问题在于,父节点只接收来自一个子节点的信号,然后阻塞等待第二个子节点的信号,但它们不会出现 . 有什么想法吗 #include <stdlib.h> #include <stdio.h> #include

所以,我的任务是以这种方式同步父母和他的两个孩子: 一个子系统向父系统发送SIGUSR2信号,然后阻塞等待的父系统消息。 同步由全局标志实现,因此父级等待任何标志变为1(在子级发送SIGUSR2时发生),然后向该子级发送信号SIGUSR1,子级恢复(导致全局标志变为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;
}
#包括
#包括
#包括
#包括
#包括
#定义LPC10
pid_t ch[2];
sig_原子标志[2]={0,0};
sig_原子标志p=0;
int get\U ind(pid\U t ch\U pid){
int i;
对于(i=0;i<2;++i){
if(ch_pid==ch[i])
返回i;
}
返回-1;
}
void usr_处理程序(int signo、siginfo_t*si、void*未使用){
int CHU指数;
开关(信号){
案例信号2:
ch_索引=获取索引(si->si_pid);
如果(Chu索引>=0)
flag_ch[ch_index]=1;
其他的
fprintf(标准,“非从子pid%d\n处理的信号”,si->si_pid);
打破
案例SIGUSR1:
标志p=1;
打破
}
}
void set\u usr\u处理程序(void){
struct-sigaction-sa;
sa.sa_sigaction=usr_handler;
sa.sa_flags=sa_SIGINFO;
sa.sa_restorer=NULL;
sigemptyset(和sa.sa_面具);
如果(0!=sigaction(SIGUSR1,&sa,NULL))
中止prg(“信号[SIGUSR1]错误”);
如果(0!=sigaction(SIGUSR2,&sa,NULL))
中止prg(“信号[SIGUSR2]错误”);
}
无效子进程(无效){
int i;
对于(i=0;i子级)
出口(1);
if(0==子级){
child_proc();
返回0;
}
ch[i]=儿童;
}   
父进程();
返回0;
}

我猜在一些全局变量声明中缺少了
volatile
。例如,
flag\u p
不是
volatile
意味着循环

while (flag_p == 0) { }
可以永远运行:GCC可能会编译它,以便只将全局变量加载到寄存器中一次,然后循环,直到该寄存器不为零(这永远不会发生)

保守的近似方法是,您应该将从信号处理程序读取或写入的所有可变变量设置为volatile

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


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

您是否有意在(0==flag_p){}时写入@AnishRam否,子对象在父对象中获取的值是子对象pid。'while(0==flag_p){};'阻止子项,直到父项的信号解除,但标志\u p未相互连接。每个进程都有自己的标志,这就是为什么我使用父进程发送给子进程的信号SIGUSR1来更改标志值的原因。谢谢您的回复。我不明白的是,当两个孩子同时向父母发送信号时。您确定处理程序将执行一次吗?如果是这样,这个问题的解决方案是什么?事实上,我添加了“volatile”,但它对我没有帮助