【问题标题】:How to read stdout from a subprocess when the latter does not flush its stdout?当子进程不刷新其标准输出时,如何从子进程中读取标准输出?
【发布时间】:2014-09-03 23:38:47
【问题描述】:

在下面的代码之前我会这样做:

  • 创建 1 个管道以读取分叉进程的输出

  • fork()

  • execv() 一个 python 脚本

然后在我做的父进程中:

//set pipes to non-Blocking
File * cout_f = fdopen(cout_pipe[0], "r");
int flags = fcntl(cout_pipe[0], F_GETFL, 0);
fcntl(cout_pipe[0], F_SETFL, flags|O_NONBLOCK);

// read from pipe and send it up through a callback method
int stat;
size_t size = 0;
char buffer [ 1000 ];
do
{
    while((size = fread(buffer, sizeof(char), sizeof(char)*1000, cout_f))!=0)
    {
        call_back_function(buffer, size);
    }
}while(waitpid(child_pid, &stat, WNOHANG) != -1)

//Do 1 extra read
while((size = fread(buffer, sizeof(char), sizeof(char)*1000, cout_f))!=0)
{
    call_back_function(buffer, size);
}

我面临的问题发生在子进程打印到标准输出并在刷新之前(通常)退出时。我想念管道中发送的内容。

这是我的问题:

  • 上面的代码安全/正确还是可以改进?
  • 有没有办法在子进程死亡的最后一刻读取整个管道,即使它没有刷新其标准输出?

【问题讨论】:

  • 只要数据不刷新就不会写入,所以没办法!
  • 同意!但是一旦python子进程死亡,管道不应该自动刷新吗?
  • 我看不出将管道设置为非阻塞模式的意义。您没有阅读错误流。您在直播结束之前不会阅读。
  • 您无需等待。只需在阅读时发送所有内容。这就是您的代码已经完成的工作。摆脱非阻塞模式;摆脱 while(wait(...)) 条件;摆脱最后的阅读;并且只执行第一个读取循环直到流结束。然后调用wait()获取退出码。
  • 可能是这样,但如果该进程也在 stderr 上产生,则需要在另一个线程中读取,否则当 stderr 缓冲区填满时,它将阻塞。

标签: c++ c fork pipe stdout


【解决方案1】:

您不必等待。只需在阅读时发送所有内容。这就是您的代码已经完成的工作。摆脱非阻塞模式;摆脱 while(wait(...)) 条件;摆脱最后的阅读;并且只执行第一个读取循环直到流结束。然后调用wait()获取退出码。

如果进程也在 stderr 上产生,则需要在另一个线程中读取,否则当 stderr 缓冲区填满时,它将阻塞。

【讨论】:

  • 你是对的,我确实读过stderr。那么我的问题可以通过上述实现解决吗?
  • 或者,如果您不想要第二个线程,您可以使用 select 系统调用等待任一管道上的数据可用。
  • 但我不明白的是上面代码中的问题。我不明白出了什么问题,所以我可以修复它。有什么想法吗?
  • @Kam 您将阅读以这种方式写入和刷新的所有内容。上面代码的问题是它的问题太多了,我在cmets中命名了几个。
  • +1 表示“摆脱非阻塞模式”;这是问题的关键。
最近更新 更多