【问题标题】:SIGPIPE in a simple two process programSIGPIPE 在一个简单的两进程程序中
【发布时间】:2013-03-18 16:50:02
【问题描述】:

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

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);

    }
}

【问题讨论】:

    标签: c pipe fork sigpipe


    【解决方案1】:

    如果您在管道上写入时收到 SIGPIPE,这意味着没有进程可以从管道中读取:当前进程也没有(您已经关闭了管道的读取端 - 这很好;您会如果您没有关闭它,则死锁而不是死锁)或其他(子)进程。

    由于您没有显示函数 foo() 的作用,因此我们无法告诉您更多问题所在。


    现在已经添加了foo(),不清楚是什么情况。有一些问题,但大多数都不是节目塞。

    1. 参数dirname 未使用。
    2. 参数out 未使用。
    3. 您在循环中泄漏了分配给sep 的内存。
    4. 您不能确保从管道读取的字符串以空值结尾。这可能会导致崩溃,进而导致写入失败。

    我怀疑第 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
    

    请注意,这是有效的,因为字符串 WHAT 末尾的 '\0' 被写入管道,并从管道中读取。大多数情况下,您不会编写包含结尾'\0' 的字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-18
      • 2014-08-20
      • 1970-01-01
      • 1970-01-01
      • 2016-08-28
      • 2014-10-14
      • 1970-01-01
      • 2014-04-08
      相关资源
      最近更新 更多