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

waiting for popen subprocess to terminate before reading

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

我正在将描述符(来自对 popen 返回的 FILE * 调用的 fileno())传递给调用 fstat() 的函数,并使用返回的值来确定要读取的量。令人惊讶的是,如果有延迟(例如,单步调试调试器),但如果在 popen 后立即调用,returns 文件大小为零,这实际上会起作用。所以我需要一些方法来等待所有输出准备就绪 - 我该怎么做?我假设我不能调用 pclose() 即使它在等待,因为这样描述符就不再有效了。

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

在类似 unix 的 LOSes 中,父进程在其子进程终止时收到 SIGCHLD。参见 this tutorial

你也可以select() on the pipe descriptor to check if there's a data to read. When the pipe is closed a "read-ready" event with zero-size data is generated.

这行不通(至少在 Linux 系统上行不通)。

文件描述符(由 fileno(3)) of a popen(3)-ed command is a pipe(7). So it is not seekable, and fstat(2) 给出,不会给出任何重要的大小。

如果您需要如此细粒度的信息,请不要使用 popen,而是调用底层系统调用 pipe(2), fork(2), execve(2), waitpid(2) then you can use poll(2)

如果你坚持使用 popen 你仍然可以 poll 它的 fileno;然而,没有标准的方法来获取它的 pid(使用 waitpid)这就是为什么你应该直接使用 syscalls(2)

我猜 fstat-ing 一个管道不应该给出一个普通文件,而是一个 fifo(7) 如果它成功,所以 st.st_mode & S_IFMT == S_IFIFO 上的特殊情况来检测这种情况。

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

如果您不从管道读取,子进程很可能永远不会终止。管道两端之间的缓冲区相当小。因此,当子进程写入输出时,缓冲区将填满并且子进程将阻塞在 write() 调用中。那么你就会陷入僵局。父进程在从管道读取之前正在等待子进程终止,子进程被阻塞,直到父进程从管道读取,因此无法终止。

我不知道这是否有帮助,但我想存储 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.