等待popen子进程在读取之前终止

时间:2015-04-10 05:30:07

标签: c macos popen

如何判断popen启动的流程何时完成?

我将描述符(从在popen返回的FILE *上调用的fileno())传递给调用fstat()的函数,并使用返回的值来确定要读取的内容。令人惊讶的是,如果存在延迟(例如,单步执行调试器),这实际上有效,但如果在popen之后立即调用,则返回文件大小为零。所以我需要一些方法来等待所有输出准备好 - 我该怎么做?我假设我不能调用pclose(),即使它等待,因为那时描述符不再有效。

更新:实际上,如果我假装管道调用上的fstat()失败,似乎代码工作正常 - 问题似乎是fstat()没有失败,正如预期的那样。所以我真正想要的是一种判断描述符是否为管道的方法 - fstat返回st_mode = 0(期待S_IFIFO!)

5 个答案:

答案 0 :(得分:2)

这不起作用(至少在Linux系统上不行)。

fileno(3) - ed命令的文件描述符(由popen(3)给出)是pipe(7)。所以它不可寻找,fstat(2)不会给它任何重要的大小。

如果您需要这些细粒度的信息,请不要使用popen,而是调用基础系统调用pipe(2)fork(2)execve(2)waitpid(2)然后您可以使用poll(2)

如果您坚持使用popen,您仍可以poll fileno;但是没有标准的方法来获取它的pid(使用waitpid)这就是你应该直接使用syscalls(2)的原因。

我想fstat - 管道不应该提供普通文件,如果成功则不应该为fifo(7),因此st.st_mode & S_IFMT == S_IFIFO上的特殊情况会检测到这种情况。

答案 1 :(得分:2)

如果您没有从管道中读取,则子流程很可能从不终止。管道末端之间的缓冲区相当小。因此,当子进程写入输出时,缓冲区将填充,子进程将在write()调用中阻塞。然后你就会陷入僵局。父进程在从管道读取之前等待子进程终止,子进程被阻塞,直到父进程从管道读取,因此无法终止。

答案 2 :(得分:1)

在类似unix的操作系统中,父进程在其子进程终止时收到SIGCHLD。见this tutorial

您还可以在管道描述符上select()检查是否有要读取的数据。当管道关闭时,“读取就绪”事件的数据为零is generated

答案 3 :(得分:1)

也许您有一些特殊的原因想要从popen确定管道上可用的数据量,但这通常不可用,而不是预期的用例。 popen(在读取模式下)旨在与尽可能快地输出数据流的程序一起使用(注意:如果你不在,它们的缓冲区填满时它们会在管道上阻塞#39} ; t立即阅读)然后在他们完成后退出,为您的读者生成EOF。这给你很大的灵活性;您可以使用基于行的读取函数,例如fgetsgetline,读取while流直到EOF,或者使用fread读取大块并准备好进行简短的读取最后一个。

答案 4 :(得分:0)

我不知道这是否有帮助,但是在类似的情况下,我想存储popen()的输出。

void live(void) { // scan and read the dongle
  FILE *dong;  // dongle
  char *c;
  char cmd[] = "rtl_power -f 88M:108M:5k -1 -";
  c = buf;  // externally allocated buffer
  dong = popen(cmd,"r");
  while (!feof(dong)) {
    *c = fgetc(dong);
    c++;
  }
  pclose(dong);
  textsize = (int) (c-buf);
  printf("Read %i bytes\n",textsize);
}

有点拖尾文件,将其复制到buf []。它已经工作了几天,我什至在Sourceforge上发布了该程序。运行Linux,Debian和Raspbian。