这是一个展示我问题的最小例子。我有一个程序分支新的子进程并将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);
}
有人可以解释为什么第一个版本不起作用吗?