信号处理程序读取错误值

时间:2015-03-09 10:57:40

标签: c signals fork

收到SIGUSR1信号后,我想显示孩子从管道中读取的值。

有一点问题。尽管getppid()被父进程写入管道,但它总是显示0。有解决方案吗 `

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

char bufP[10], bufC[10];
int gpid;

void handler(int signum){
    signal(SIGUSR1, handler);
    if (signum == SIGUSR1){
        printf("SIGUSR1 received\n");
        gpid = atoi(bufC);
        printf("Grandparent: %d\n", gpid);
        exit(0);
    }   
}

int main(void){
    int pid, fd[2];
    pipe(fd);
    pid = fork();

    signal(SIGUSR1, handler);

    if (pid == 0){
        //child
        close(fd[1]);       
        read(fd[0], bufC, sizeof(bufC));                
        close(fd[0]);
    }else{
        //parent
        close(fd[0]);
        sprintf(bufP, "%d", getppid());
        write(fd[1], bufP, sizeof(bufP));
        kill(pid, SIGUSR1);     
        close(fd[1]);
    }

}

`

感谢您的回复。

2 个答案:

答案 0 :(得分:1)

您好像假设在<{em> read()完成后将始终处理信号,但实际情况并非如此。信号本质上是异步,可以随时到达(甚至是read()的中途!)。基本上你是在一个所谓的竞争条件上构建你的程序,你真的应该避免。

答案 1 :(得分:0)

虽然这里确实存在竞争条件,但并不是造成麻烦的原因。问题是在子进程中的read()调用被阻止时会触发您的信号。您可以在父进程中添加足够长的暂停以让子进程read()完成:

if (pid == 0){
    //child
    close(fd[1]);       
    read(fd[0], bufC, sizeof(bufC));                
    close(fd[0]);
    sleep(10); // wait for the signal to arrive
}else{
    //parent
    close(fd[0]);
    sprintf(bufP, "%d", getppid());
    write(fd[1], bufP, sizeof(bufP));
    close(fd[1]); // close right away to be sure the buffers are flushed
    sleep(1); // make sure the child has finished reading the buffer
    kill(pid, SIGUSR1);     
}

当然,关于种族状况的评论以及你应该避免它们的事实仍然是正确的。此代码不是“生产质量”,如果系统负载过重,1秒不足以安排子进程并完成read()调用,则代码将失败。