1

我有一个简单的叉子和管道设置,我以前使用过。但这一次,我接到了一个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);

    }
}
4

1 回答 1

2

如果在管道上写入时获得 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(简短、独立、正确的示例)时,这很麻烦。当测试用例被简化为一个可以编译和运行的简单程序时,提交者确信问题会随之重现,这会容易得多。


此 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'

于 2013-03-18T16:54:01.373 回答