繁体   English   中英

读取管道块,直到在管道末端运行的程序终止 - Windows

[英]read on a pipe blocks until program running at end of pipe terminates - Windows

我有一个示例程序,每秒输出一行文本。 在下面的测试程序中,该程序将一些文本写入stdout然后等待 1 秒并重复 20 次。

我有另一个程序,它使用popen (Windows 上的_popen )打开管道以从程序中读取。 然后我使用fgets来读取数据。 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);
    }
}

为什么fgets阻塞?

因为它在等待孩子们输出一些东西。

测试程序会立即打印一些文本,那么为什么fgets不立即读取第一行文本呢?

它实际上不会立即打印文本。 正如@Barmar 所注意到的,这里的问题是写入管道是由 C 标准库实现缓冲(而不是缓冲)的。 这种缓冲发生在您的子程序 ( 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);
    }
}

你真的没有太多可以做的了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM