最常见的原因是您没有关闭管道的写入端,因此 EOF 永远不会被发送。常见的示例是当您的代码如下所示:
int fds[2];
pipe(fds); // open a pipe
if (fork()) {
// parent process
write(fds[1], ... // write data
close(fds[1]); // close it
} else {
// child process
while (read(fds[0], ....) > 0) {
// read until EOF
这里的问题是管道的写端永远不会关闭——父进程关闭它,但子进程仍然打开写描述符。所以孩子永远不会在读取描述符上看到 EOF。
在 fork 子节点后,您需要做的第一件事是 close(fds[1]);,关闭其写入描述符的副本。这样,当父级关闭对管道写入端的最后一个剩余引用时,子级将在读取端看到 EOF。
编辑
查看您添加的链接,这正是问题所在 - 子项在其标准输出上仍然打开了管道的写入端。不要将写入端复制到孩子的标准输出,只需将其关闭即可。将标准输出发送到其他地方(日志文件或 /dev/null)
编辑
对于双向通信,您需要两个管道:
int tochild[2], fromchild[2];
pipe(tochild); pipe(fromchild);
if (fork()) {
close(tochild[0]);
close(fromchild[1]);
//write to tochild[1] and read from fromchild[0]
} else {
dup2(tochild[0], 0);
dup2(fromchild[1], 1);
close(tochild[0]); close(tochild[1]);
close(fromchild[0]); close(fromchild[1]);
exec(...
}
但是,您需要非常小心地在父级中写入数据——如果要写入大量数据
发送给孩子,您不能在读取孩子的输出之前发送所有内容,否则您可能会死锁(两个管道都已填满,父块试图为孩子写更多数据,而孩子块试图输出)。您需要使用 poll 或 select 来判断何时有数据要读取或有空间要写入,并且您可能希望将管道(至少父级结束)置于非阻塞模式。