【问题标题】:Redirecting stdin to children makes the program not terminate将标准输入重定向到子进程使程序不会终止
【发布时间】:2020-04-10 11:06:35
【问题描述】:

我一直在尝试做的是设置一个分叉两个孩子的程序。父进程从标准输入读取,然后通过管道将其重定向到其子进程。然后子进程复制管道的读取端,以便它可以从标准输入(而不是管道)读取,然后将其打印到标准输出中。代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char **argv) {
    char buf[100];
    int pipe_one[2];
//    int pipe_two[2];

    pipe(pipe_one);
//    pipe(pipe_two);

    // First child
    switch(fork()) {
        case -1:
            exit(EXIT_FAILURE);
        case 0:
            close(pipe_one[1]);
            dup2(pipe_one[0], STDIN_FILENO);
            close(pipe_one[0]);
            while (fgets(buf, 100, stdin)) {
                fputs(buf, stdout);
            }
            fflush(stdout);
            exit(EXIT_SUCCESS);
        default:
            break;
    }

    // Second child
/*    switch(fork()) {
        case -1:
            exit(EXIT_FAILURE);
        case 0:
            close(pipe_two[1]);
            dup2(pipe_two[0], STDIN_FILENO);
            close(pipe_two[0]);
            while (fgets(buf, 100, stdin)) {
                fputs(buf, stdout);
            }
            fflush(stdout);
            exit(EXIT_SUCCESS);
        default:
            break;
    }*/

    close(pipe_one[0]);
//    close(pipe_two[0]);
    FILE *out_1 = fdopen(pipe_one[1], "w");
//    FILE *out_2 = fdopen(pipe_two[1], "w");

    while (fgets(buf, 100, stdin)) {
        fputs(buf, out_1);
//        fputs(buf, out_2);
    }

    fflush(out_1);
//    fflush(out_2);
    fclose(out_1);
//    fclose(out_2);
    close(pipe_one[1]);
//    close(pipe_two[1]);

    wait(NULL);
    //wait(NULL);

    exit(EXIT_SUCCESS);
}

我已经注释掉了与第二个孩子有关的所有部分。如果我运行这个程序,它可以完美运行(它从标准输入读取直到遇到 EOF,然后将其打印到标准输出中)。但是,如果我尝试用第二个 fork 做完全相同的事情(请参阅注释掉的部分),它会做完全相同的事情,只是在打印完所有内容后程序不会终止。而且我一直找不到原因。

我的猜测是我不会在两个孩子中重复 stdinfileno 两次。然而,我们的任务要求我们这样做。有什么我想念的吗?如果有人可以看一下,我真的很高兴!

【问题讨论】:

    标签: c unix pipe fork


    【解决方案1】:

    只有在写入端的所有描述符都关闭后,管道的读取端才会到达 EOF。

    您不会在第一个孩子中关闭 pipe_two[0],因此第二个孩子在第一个孩子完成之前不会退出。

    您不会在第二个孩子中关闭 pipe_one[0],因此第一个孩子要等到第二个孩子关闭后才会退出。


    顺便说一句,

    最好在第一个孩子中关闭pipe_two[1]

    在第二个孩子中关闭pipe_one[1]会很好。

    还有,

    dup2(pipe_one[0], STDIN_FILENO);
    close(pipe_one[0]);
    while (fgets(buf, 100, stdin)) ...;
    

    可以简化为

    FILE *f = fdopen(pipe_one[0]);
    while (fgets(buf, 100, f)) ...;
    

    【讨论】:

    • 非常感谢!我没有意识到我还必须关闭我根本不使用的管道。
    • Re“我没有意识到我也必须关闭我根本不使用的管道。”,这是一个奇怪的事情,因为你关闭了@ 987654327@ 在第一个孩子中,即使你不使用它。
    • 是的,我的意思是因为我从不在第一个孩子中使用 pipe_two,所以我也永远不必关闭它(只有 pipe_one 未使用的末端,因为这是我正在使用的一个管道) .但现在我想起来了,我必须关闭所有东西才有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2016-02-29
    • 2022-12-14
    • 2020-10-01
    • 1970-01-01
    • 2013-06-02
    相关资源
    最近更新 更多