我有一个非常简单的c / c ++程序,它强制子进程执行另一个程序,然后将一些数据发送到该子程序,并等待响应。
子程序从stdin读取并在继续之前等待EOF。
我的问题是,子程序从管道写入接收初始输入,但它从未看到EOF(即使我关闭了管道),所以它会永远等待。
我不确定为什么关闭管道并不意味着孩子的标准输入的EOF?
这是代码:
答案 0 :(得分:6)
最常见的原因是您没有关闭管道的写入端,因此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。
分叉子项后,您需要做的第一件事是close(fds[1]);
,关闭其写入描述符的副本。这样,当父级关闭对管道写入端的最后一个剩余引用时,子级将在读取端看到EOF。
修改强>
查看您添加的链接,这正是问题 - 孩子仍然在其标准输出上打开管道的写入结束。不要将写入结束复制到子项中的stdout,只需将其关闭即可。在其他地方发送stdout(日志文件或/ 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来判断何时有要读取的数据或要写入的空间,并且您可能希望将管道(父项至少结束)置于非阻塞模式。
答案 1 :(得分:3)
更新了我认为的问题: 您正在阅读角色并检查该角色的EOF。这不是read()系统调用的工作原理。在EOF时它将返回0。它不会将EOF写入缓冲区。
我也看到你一次只读一个角色。这是一种读取数据的糟糕方式。它比读取大缓冲区(比如4或8 kB)要快几倍
。我相信你在这里也有一个共同的错误。您没有检查write()的返回值。
写入系统调用不保证在返回之前写入所有数据。它可能会写入4000个字节并返回。它将返回写入的字节数。然后,您有责任更新缓冲区指针并再次调用write。
或者它可能会返回错误代码,因此您必须检查错误代码。
答案 2 :(得分:-1)
这是我为你写的概念证明: