SIGPIPE在一个简单的两个过程程序中

时间:2013-03-18 16:50:03

标签: c pipe fork sigpipe

我有一个简单的设置,我之前使用过叉子和管道。但这一次我在SIGPIPE电话中收到了write。这是代码

int fd[2];

int pid;

if (pipe(fd) == -1) {
    perror("pipe init error"); 
    exit(1);
}


// signal(SIGPIPE, SIG_IGN);
if ((pid = fork()) < -1) {
    perror("fork error"); exit(1);
}
// parent
else if (pid > 0) {
    close(fd[0]); 

    write(fd[1], "WHAT", MAXWORD); //SIGPIPE here

    close(fd[1]);
    int status;
    wait(&status);
}

// child
else {
    close(fd[1]);
    // void foo(char *dirname, int in, int out);
    // foo takes a path, reads from fd 'in' and outputs to 'fd' out
    foo("./some/path", fd[0], 1);
    close(fd[0]);
}

这是函数foo:

void foo(char *dirname, int in, int out){

    int string_length;
    char word[MAXWORD];

    // to get rid of \n
    char* sep;
    sep = malloc(sizeof(char));


    // read from piped stdin until it's closed
    while ((string_length = read(in, word, MAXWORD)) > 0){

        // get rid of \n
        sep = strchr(word, '\n');
        *sep = '\0';

        printf("THe word is: %s\n", word);

    }
}

1 个答案:

答案 0 :(得分:2)

如果在管道上写入时收到SIGPIPE,则表示没有可以从管道读取的进程:当前进程(您已关闭管道的读取端 - 这是好的;您是如果你没有关闭它,那么就会陷入僵局,而不是另一个(孩子)过程。

由于您没有显示foo()函数的功能,我们无法告诉您更多有关错误的信息。


现在添加了foo(),目前还不清楚是什么。有问题,但大多数都没有显示停止者。

  1. 参数dirname未使用。
  2. 参数out未使用。
  3. 泄漏分配给循环中sep的内存。
  4. 您不能确保从管道读取的字符串为空终止。这可能会导致崩溃,从而导致写入失败。
  5. 我怀疑第4项是关键问题;其他更重要的是整洁。

    我注意到在主代码中,你有:

    write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
    

    除非MAXWORD是4或5,否则你正处于失败之路;你应该只写4或5个字符。

    结合read() ...读取将尝试读取MAXWORD字节,但可能会减少。但是,没有迹象表明所写的数据包含换行符,因此在输入中搜索换行符不会可靠地运行。但是,这个问题应该在管道成功写入之后显现出来,而不是之前。

    我注意到变量int fd_parent_write_word[2];未使用,代码使用变量int fd[2]而没有声明它。

    当您分析的内容不是SSCCE(Short, Self-Contained, Correct Example)时,这会令人讨厌。当测试用例被简化为一个简单的程序时,它就会变得容易得多,该程序可以通过提交者编译和运行,确信问题可以通过它重现。


    此SSCCE代码编译干净并运行正常:

    #include <assert.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    enum { MAXWORD = 5 };
    
    static void foo(int in);
    
    static void he_who_pays_the_piper(int signum)
    {
        assert(signum == SIGPIPE);
        const char msg[] = "Received signal SIGPIPE\n";
        write(2, msg, sizeof(msg)-1);
        exit(1);
    }
    
    int main(void)
    {
        int fd[2];
        int pid;
    
        if (pipe(fd) == -1) {
            perror("pipe init error"); 
            exit(1);
        }
    
        signal(SIGPIPE, he_who_pays_the_piper);
        if ((pid = fork()) < -1) {
            perror("fork error"); exit(1);
        }
        else if (pid > 0) {
            close(fd[0]); 
            write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
            close(fd[1]);
            int status;
            pid = wait(&status);
            printf("Got status 0x%04X from %d\n", status, pid);
        }
        else {
            close(fd[1]);
            foo(fd[0]);
            close(fd[0]);
        }
        return 0;
    }
    
    
    static void foo(int in)
    {
        int string_length;
        char word[MAXWORD];
    
        while ((string_length = read(in, word, MAXWORD)) > 0)
            printf("The word is: %.*s\n", string_length, word);
    }
    

    示例输出:

    The word is: WHAT
    Got status 0x0000 from 49458
    

    请注意,这是有效的,因为字符串'\0'末尾的WHAT被写入管道,并从管道中读取。通常,您不会编写包含尾随'\0'的字符串。