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

标签 c linux ipc popen blocking

我有一个示例程序,每秒输出一行文本。在下面的测试程序中,该程序向 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);
    }
}

最佳答案

Why does fgets block?

因为它在等待 children 输出一些东西。

The test program does print some text immediately, so why doesn't fgets read this first line of text immediately?

它实际上不会立即打印文本。问题在这里,如@Barmar注意,写入管道是由 C 标准库实现缓冲的(而不是 line 缓冲的)。这种缓冲发生在您的子程序 (helloworld) 中,而不是在您的父程序 (pipe_test) 中。

在您的父程序中,您无法控制通过 popen() 产生的 child 会做什么,因此如果 child 输出像这种情况一样被缓冲,您唯一能做的是(不修改 child 的代码)是等到缓冲区被刷新到管道。

为了更快地获得输出,您必须修改子代码以手动调用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);
    }
}

您真的无能为力。

关于c - 读取管道 block ,直到在管道末端运行的程序终止 - Windows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59828628/

相关文章:

linux - 使用端口转发重新启动后连接 ssh

linux - 如何在 UNIX 中使用安全复制保存所有权

c - 8 皇后片段

c - OS X锁屏用纯C?

linux - 在 chroot 环境中调用外部脚本

c++ - IPC:在两个程序之间使用 C++ 中的命名管道

android - bindService() 返回 false 但需要调用 unbindService()?

c - 这段代码的 sublime text 2 有什么问题?

c - 值 1.0e+1 的类型是什么

javascript - Node `net` 模块 IPC 服务器间歇性