简体   繁体   English

SIGPIPE在一个简单的两处理程序中

[英]SIGPIPE in a simple two process program

I have a simple setup for a fork and pipe that I have used before. 我为以前使用过的叉子和烟斗做了一个简单的设置。 But this time around I'm getting a SIGPIPE in my write call. 但是这次我在write调用中得到了一个SIGPIPE Here's the code 这是代码

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

Here's function foo: 这是函数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);

    }
}

If you get SIGPIPE when you write on a pipe, it means there is no process that can read from the pipe: neither the current process (you've close the read end of the pipe — which is good; you'd be deadlocked instead of dead if you'd not closed it) nor the other (child) process. 如果在管道上进行写操作时获得SIGPIPE,则意味着没有可以从管道读取的进程:当前进程(关闭了管道的读取端,这都很好–很好;您将陷入僵局) (如果您不关闭该文件,则不会死亡)或其他(子)进程。

Since you've not shown what the function foo() does, we can't tell you any more about what's wrong. 由于您尚未显示函数foo()功能,因此我们无法再告诉您有什么问题。


Now that foo() has been added, it is not clear what's up. 现在已经添加了foo() ,现在还不清楚是怎么回事。 There are issues, but most are not show stoppers. 有问题,但大多数没有显示塞子。

  1. Argument dirname is unused. 参数dirname未使用。
  2. Argument out is unused. out未使用。
  3. You leak the memory allocated to sep in the loop. 您会在循环中泄漏分配给sep的内存。
  4. You do not ensure that the string read from the pipe is null terminated. 您不能确保从管道读取的字符串以null结尾。 This could lead to crashes, which in turn would lead to writes failing. 这可能会导致崩溃,进而导致写入失败。

I suspect item 4 is the immediately critical issue; 我怀疑第4项是紧迫的问题。 the others are more matters of tidiness. 其他则比较整洁。

I note that in the main code, you have: 我注意到在主代码中,您有:

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

Unless MAXWORD is either 4 or 5, you are on a losing path; 除非MAXWORD为4或5,否则您将处于失败的道路; you should only write 4 or 5 characters. 您只能输入4或5个字符。

Combined with the read() ...the read will attempt to read MAXWORD bytes but might get fewer. read()结合使用...读取将尝试读取MAXWORD字节,但可能会更少。 However, there's no sign that the data written contains a newline, so the search for a newline in the input is not going to work reliably. 但是,没有迹象表明写入的数据包含换行符,因此在输入中搜索换行符将无法可靠地进行。 However, that problem should manifest itself after the pipe was successfully written too, not before. 但是,该问题也应该在管道成功写入之后而不是之前成功显现。

I note that the variable int fd_parent_write_word[2]; 我注意到变量int fd_parent_write_word[2]; is unused and the code uses variable int fd[2] without declaring it. 未使用,并且代码使用变量int fd[2]而不声明它。

It is a nuisance when what you get to analyze is not an SSCCE ( Short, Self-Contained, Correct Example ). 当您要分析的内容不是SSCCE( 简短,自包含,正确的示例 )时,这很麻烦。 It is so much easier when the test case has been reduced to a simple program that can be compiled and run with the submitter confident that the problem reproduces with it. 当测试用例简化为可以编译并运行的程序时,提交者确信问题会重现,这将变得非常容易。


This SSCCE code compiles cleanly and runs OK: 此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);
}

Example output: 输出示例:

The word is: WHAT
Got status 0x0000 from 49458

Note that this works because the '\\0' at the end of the string WHAT is written to the pipe, and read from the pipe. 请注意,这是有效的,因为字符串WHAT末尾的'\\0'已写入管道,并从管道读取。 Most usually, you do not write the strings including the trailing '\\0' . 通常,您不编写包含结尾'\\0'的字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM