假设我有这个示例代码(为了清楚起见,错误检查在很大程度上被省略)
static void c_way() {
int pipefd[2], ch;
FILE *rf, *wf;
pipe(pipefd);
switch (fork()) {
case -1:
/* something went wrong */
break;
case 0:
dup2(pipefd[0], STDIN_FILENO);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]);
close(pipefd[1]);
execvp(cat_args[0], cat_args);
_exit(0);
}
rf = fdopen(pipefd[0], "r");
wf = fdopen(pipefd[1], "w");
fprintf(wf, "I have %d apples.\n", 5);
fclose(wf);
while ((ch = fgetc(rf)) != EOF)
putchar(ch);
puts("Done reading.");
fflush(stdout);
fclose(rf);
}
其中cat_args
只是{"cat", "-", NULL}
。出于某种原因,尽管关闭了父进程的管道结束,但似乎永远不会在fgetc
循环中到达EOF,就像子进程正在等待更多输入一样。我忘记关闭一些文件描述符了吗?即使不使用文件指针(即原始POSIX读写),它仍然会挂起。
我看到一些类似的回答问题,所以这可能是重复的。
答案 0 :(得分:1)
当我运行此代码时,我看到:
[notroot]$ ./c_way
I have 5 apples.
然后挂起。
它是一场竞赛:你的父进程在子进程执行的 cat 之前从管道中读取自己刚刚写入的数据(并将其写入stdout)。
孩子什么都不读 - 管道已被父母排干 - 因此耐心地阻止stdin等待输入。与此同时,父母在管道的读取端耐心地阻塞,等待输入永远不会到达。
您需要两个管道:一个用于将父级连接到子级stdin,另一个用于将子级stdout连接到父级。 (另见socketpair。)