为什么在管道的读取端关闭时不会发生SIGPIPE?

时间:2018-01-31 14:47:57

标签: c linux process signals

我正在尝试编写一个包含两个进程的程序:

一个进程生成一些a + b问题并将其打印到stdout(如printf("%d %d\n", a, b)),并通过stdin从另一个进程获得答案,并将答案记录到log.txt。当询问所有问题时,该过程将打印出“-1 -1”以指示问题的结束。

另一个进程通过stdin(如scanf("%d%d", &a, &b))接收a + b问题,并将答案打印到其stdout。当a = b = -1进程退出时。

我正在使用两对管道来连接这两个进程。我使用dup2将管道绑定到stdin和stdout。我的源代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>

// Get a + b question through stdin, and print answer to stdout
void calc_a_plus_b() {
    int a, b;
    while (scanf("%d%d", &a, &b) > 0)
    {
        if (a == -1 && b == -1)
            break;
        printf("%d\n", a + b);
        fflush(stdout);
    }
}

// Ask a + b through stdout, and get answer through stdin
// Log answer to log.txt
void ask_a_plus_b() {
    FILE* log = fopen("log.txt", "w");
    int i, a, b, c;
    for (i = 0; i < 3; i++) {
        a = i; b = i + 1;
        printf("%d %d\n", a, b);
        fflush(stdout);
        scanf("%d", &c);
        fprintf(log, "%d\n", c);
    }
    printf("-1 -1\n");
    fclose(log);
}

int main()
{
    pid_t ask_pid, calc_pid, term_pid;
    int ask_to_calc[2], calc_to_ask[2];    // Two pairs of pipe
    int status;

    // Create pipe
    pipe(ask_to_calc); pipe(calc_to_ask);

    // Create calculate process
    calc_pid = fork();
    if (calc_pid == 0) {
        // Close useless pipe
        close(ask_to_calc[1]);
        close(calc_to_ask[0]);

        // Bind pipe to stdin and stdout
        dup2(ask_to_calc[0], 0);
        dup2(calc_to_ask[1], 1);
        close(ask_to_calc[0]);
        close(calc_to_ask[1]);

        calc_a_plus_b();
        return 0;
    }

    // Create ask process
    ask_pid = fork();
    if (ask_pid == 0) {
        // Close useless pipe
        close(ask_to_calc[0]);
        close(calc_to_ask[1]);

        // Bind pipe to stdin and stdout
        dup2(calc_to_ask[0], 0);
        dup2(ask_to_calc[1], 1);

        ask_a_plus_b();
        return 0;
    }

    // Wait for children to exit
    while ((term_pid = wait(&status)) > 0) {
        if (WIFSTOPPED(status))
        {
            // If child stopped but hasn't exited, ignore
            continue;
        } else if (WIFSIGNALED(status)) {
            // Child exited due to signal
            printf("%s terminated due to signal %d\n", ask_pid == term_pid ? "ask" : "calc", WTERMSIG(status));
        } else {
            // Child exited normally
            printf("%s terminated normally\n", ask_pid == term_pid ? "ask" : "calc");
        }
    }
    return 0;
}

此代码正常运行,并打印出

calc terminated normally
ask terminated normally

man 7 pipehttp://man7.org/linux/man-pages/man7/pipe.7.html)我知道,当管道读取端的所有文件描述符都关闭,而另一个进程仍然尝试写入此管道时,将发生一个SIGPIPE 。所以我决定删除calc_a_plus_b中的所有代码,看看会发生什么。

令人惊讶的是,SIGPIPE没有发生。该程序只打印出

calc terminated normally

之后程序被卡住了。我想这是因为printf中的ask_a_plus_b被屏蔽了。

我想我已经将所有文件描述符关闭到管道ask_to_calc的读取端(我已将管道绑定到计算过程的stdin,但是进程已经退出,所以它的stdin也是关闭了吗?),那么为什么在询问过程试图写入管道时不会发生SIGPIPE?

1 个答案:

答案 0 :(得分:0)

感谢@Art的评论。我忘了在父进程中关闭管道-_-&#34;

关闭父进程中的管道后,由于SIGPIPE,请求进程现在终止。