popen与/ dev / fd / n匿名管道挂起子进程

时间:2017-04-24 10:01:47

标签: c linux

我正在尝试使用匿名管道替代子进程读取的文件。我遇到的问题是,我认为子流程会挂起,因为它不会识别"文件的结束。 (管道)已经到达。

以下是我正在做的一些示例代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/fcntl.h>

int main()
  {
  int pipefd[2];
  pipe(pipefd);
  fcntl(pipefd[0], F_SETFL, O_NONBLOCK); // necessary?

  char cmd[128];
  snprintf(cmd, sizeof(cmd), "cat /dev/fd/%i", pipefd[0]);
  printf("Command: %s\n", cmd);

#if 1
  // This works
  write(pipefd[1], "line1\n", 6);
  write(pipefd[1], "line2\n", 6);
  write(pipefd[1], "line3\n", 6);
  close(pipefd[1]);
#endif

  FILE* fp;
  if ((fp = popen(cmd, "r")) != NULL)
    {
//  fcntl(fileno(fp), F_SETFL, O_NONBLOCK);  // causes SIGPIPE

#if 0
    // This doesn't work
    write(pipefd[1], "line1\n", 6);
    write(pipefd[1], "line2\n", 6);
    write(pipefd[1], "line3\n", 6);
    close(pipefd[1]);
#endif

    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), fp) != NULL)
      printf("%s", buffer);
    printf("retcode: %i\n", pclose(fp));
    }

  close(pipefd[0]);

  return 0;
  }

上面给出的代码有效。在其中我创建了一个管道,并使用管道的读取端创建一个命令,在本例中为cat。在工作版本中,然后我将数据写入管道的写入端然后使用popen启动子流程并从子流程读取stdout直到它结束。

我需要做的是在创建子流程之后将写入移动到管道(请参阅#if 0块)。最终,它将最终成为一个单独的线程。但是,切换到popen通话后意味着子流程不会结束(挂起),我看不清楚原因。

我已尝试使各种流非阻塞,但在子流程流上执行此操作只会导致SIGPIPE失败。

有谁知道如何使这个工作?

谢谢!

1 个答案:

答案 0 :(得分:0)

之间的区别
write(pipefd[1], "line1\n", 6);
write(pipefd[1], "line2\n", 6);
write(pipefd[1], "line3\n", 6);
close(pipefd[1]);
在popen vs after之前的

是这样的:如果在调用popen时打开pipefd[1],forked / execed进程也将打开它。当该进程从pipefd[0]读取时,它将永远不会看到EOF,因为该描述符(管道的写入端)保持打开状态。

解决此问题的一个方法是为该文件描述符设置close-on-exec标志

fcntl(pipefd[1], F_SETFD, fcntl(pipefd[1], F_GETFD) | FD_CLOEXEC);

在打电话给popen之前。