在管道块上读取,直到在管道末端运行的程序终止 - Windows
Posted
技术标签:
【中文标题】在管道块上读取,直到在管道末端运行的程序终止 - Windows【英文标题】:read on a pipe blocks until program running at end of pipe terminates - Windows 【发布时间】:2020-01-20 17:54:04 【问题描述】:我有一个示例程序,每秒输出一行文本。在下面的测试程序中,该程序将一些文本写入stdout
,然后等待 1 秒并重复 20 次。
我有另一个程序使用popen
(Windows 上的_popen
)打开一个管道以从程序中读取。然后我使用fgets
读取数据。我遇到的问题是 fgets
阻塞直到程序终止。然后我一口气得到所有的输出,全部 20 行。我想一次输出一行,然后让fgets
阻塞直到下一行准备好。原因是我打算在一个将不断运行、输出文本的程序上使用它,例如喜欢使用tail
。
如果我在一个一次性输出一些文本并退出的程序上运行此代码示例,那么它可以正常工作。
为什么fgets
会屏蔽?测试程序确实会立即打印一些文本,那么fgets
为什么不立即读取第一行文本呢?
代码如下:
#include <stdio.h>
#include <windows.h>
void execute(const char* cmd)
char buffer[128] = 0 ;
FILE* pipe = _popen(cmd, "r");
if (!pipe)
printf("popen() failed!\n");
return;
while (!feof(pipe))
if (fgets(buffer, 128, pipe) != nullptr)
printf("%s", buffer);
int rc = _pclose(pipe);
if (rc != EXIT_SUCCESS) // return code not 0
printf("pclose exit failure: %d\n", rc);
int main(int argc, char* argv[])
if (argc != 2)
printf("Usage: pipe_test.exe <program>\n");
exit(1);
execute(argv[1]);
程序运行,helloworld.exe
:
#include <stdio.h>
#include <windows.h>
int main()
for (int i = 0; i < 20; i++)
printf("Hello World %d\n", i);
Sleep(1000);
【问题讨论】:
默认情况下会缓冲写入管道。使用setvbuf()
关闭缓冲或在每个printf()
之后调用fflush(stdout)
。
@Barmar 我试过 setvbuf(pipe, NULL, _IONBF, 128);创建管道后但没有效果
@Barmar 在被调用程序中 flush(stdout) 表示立即输出。不太方便,因为我更喜欢使用未经修改的调用程序,但给了我一个解决方法。我认为被调用程序中 printf 中的 \n 与 flush 相同?
@AngusComber printf 将在换行符上刷新,但仅在进入真正的标准输出设备时才会刷新。如果它被重定向,那么它会被缓冲以提高吞吐量。
***.com/questions/5431941/…
【参考方案1】:
为什么
fgets
会屏蔽?
因为它在等待孩子们输出一些东西。
测试程序确实会立即打印一些文本,那么为什么
fgets
不立即读取第一行文本呢?
它实际上不立即打印文本。正如@Barmar 所指出的,这里的问题是写入管道被C 标准库实现缓冲(而不是line 缓冲)。这种缓冲发生在您的子程序 (helloworld
) 中,而不是在您的父程序 (pipe_test
) 中。
在您的父程序中,您无法控制通过popen()
生成的子程序将执行的操作,因此如果子输出像这种情况一样被缓冲,您唯一可以做的事情(不修改子程序代码)是等到缓冲区刷新到管道。
为了更快地得到输出,你必须修改孩子的代码来手动调用fflush()
或使用setvbuf()
来禁用缓冲:
int main()
setvbuf(stdout, NULL, _IONBF, 0); // Disable buffering on stdout.
for (int i = 0; i < 20; i++)
printf("Hello World %d\n", i);
Sleep(1000);
你真的无能为力了。
【讨论】:
以上是关于在管道块上读取,直到在管道末端运行的程序终止 - Windows的主要内容,如果未能解决你的问题,请参考以下文章