stdout的奇怪行为重定向到管道

时间:2016-02-24 15:30:36

标签: c linux

这是一个展示我问题的最小例子。我有一个程序分支新的子进程并将stdout重定向到它。它工作正常。然后我分叉第二个子进程并将stdout重定向到它,然后关闭第一个管道。我希望第一个子进程在其输入管道中接收EOF并终止。相反,它会一直处于读取状态,直到主要任务退出。我不懂为什么。我希望第一个管道关闭,第一个子进程成为一个僵尸。

以下是演示此问题的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int popenin(char *command) {
    int                 pin[2];
    pid_t               pid;

    if (pipe(pin) != 0) exit(1);

    pid = fork();
    if (pid < 0) exit(1);

    if (pid == 0) {
        close(pin[1]);
        dup2(pin[0], 0);
        close(pin[0]);
        execlp("bash", "bash", "-c", command, NULL);
        perror("Error:");
        exit(1);
    } else {
        close(pin[0]);
        return(pin[1]);
    }
}

int main() {
    int fd;
    fd = popenin("gzip > foo1.gz");
    dup2(fd, 1);
    close(fd);
    printf("foo 1 content\n");fflush(stdout);
    fd = popenin("gzip > foo2.gz");
    close(1);
    dup(fd);
    close(fd);
    printf("foo 2 content\n");fflush(stdout);
    sleep(10000);
}

该程序创建了两个文件foo1.gz和foo2.gz,两个文件都是空的,并且系统中运行了两个gzip进程。我希望看到第一个文件完成,关闭,第一个gzip进程退出。

如果我按以下方式修改最小示例,它将按预期工作。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int popenin(char *command) {
    int                 pin[2];
    pid_t               pid;

    if (pipe(pin) != 0) exit(1);

    pid = fork();
    if (pid < 0) exit(1);

    if (pid == 0) {
        close(pin[1]);
        dup2(pin[0], 0);
        close(pin[0]);
        execlp("bash", "bash", "-c", command, NULL);
        perror("Error:");
        exit(1);
    } else {
        close(pin[0]);
        return(pin[1]);
    }
}

int main() {
    int fd;
    fd = popenin("gzip > foo1.gz");
    dup2(fd, 1);
    close(fd);
    printf("foo 1 content\n");fflush(stdout);
    close(1);                    // close(1) is moved before popenin
    fd = popenin("gzip > foo2.gz");
    dup(fd);
    close(fd);
    printf("foo 2 content\n");fflush(stdout);
    sleep(10000);
}

有人可以解释为什么第一个版本不起作用吗?

0 个答案:

没有答案