无法读取流直到子进程退出?

5

好的,我有一个程序可以创建两个管道 -> 分叉 -> 将子进程的标准输入和输出重定向到每个管道的一端 -> 父进程连接到管道的另一端并尝试读取与子进程输出相关联的流并将其打印到屏幕上(最终我也会让它写入子进程的输入)。

问题在于,当父进程尝试从子进程的输出流中获取fgets时,它只是停滞不前,等待子进程死亡才能获取fgets并打印输出。如果子进程没有退出,它就会永远等待。发生了什么?我以为可能fgets会阻塞直到流中有SOMETHING,但不会一直阻塞直到子进程放弃其文件描述符。

以下是代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
 FILE* fpin;
 FILE* fpout;
 int input_fd[2];
 int output_fd[2];
 pid_t pid;
 int status;
 char input[100];
 char output[100];
 char *args[] = {"/somepath/someprogram", NULL};
 fgets(input, 100, stdin); // the user inputs the program name to exec

 pipe(input_fd);
 pipe(output_fd);
 pid = fork();

 if (pid == 0) {
  close(input_fd[1]);
  close(output_fd[0]);
  dup2(input_fd[0], 0);
  dup2(output_fd[1], 1);
  input[strlen(input)-1] = '\0';
  execvp(input, args);
 }
 else {
  close(input_fd[0]);
  close(output_fd[1]);
  fpin = fdopen(input_fd[1], "w");
  fpout = fdopen(output_fd[0], "r");
  while(!feof(fpout)) {
   fgets(output, 100, fpout);
   printf("output: %s\n", output);
  }
 }

 return 0;
}

1个回答

5
孩子应该使用fflush()清除其输出,或者正确终止行。否则,I/O缓冲可能会保留数据相当长的时间。
您可以尝试在交出控制之前,在孩子的输出文件描述符上设置O_NONBLOCK标志(使用fcntl()),但这将需要您相应地更改父代码。但正如评论中指出的那样,如果孩子使用基于FILE的I/O,则无法帮助您克服C标准库级别的缓冲。

嗯,你说得对。当我刷新输出时,它可以工作。问题是,我无法控制子进程。我只能通过我的测试程序来控制它,因为我可以编辑源代码...我该如何确保任何被execvp的程序都刷新其输出或无缓冲区或其他东西... 啊! - BobTurbo
等一下,这是测试子代码:printf("请输入输入:\n"); fflush(stdout);如果我去掉/n或者fflush,它会延迟... 我需要它在没有/n的情况下读取,并且...无需我手动fflush。 - BobTurbo
问题完全在于子进程。如果孩子正在使用行缓冲IO并且没有换行符或“fflush()”地写入,则数据永远不会离开子进程 - 没有其他人能对此做任何事情。 - caf
@unwind:问题不在文件描述符选项上,而是子进程中stdio库的行为。 - caf
@caf:哎呀!当然是真的。如果客户端使用的是原始的非缓冲I/O,那么这就很重要了。 - unwind
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接