首页 > 解决方案 > 将标准输出重定向到管道并从单个进程中读取

问题描述

我正在将一个 Linux 程序移植到一个没有 fork()的系统,所以一切都在一个进程中运行。该程序创建管道,将标准输出重定向到管道的输入,分叉,子调用 printf 和父从管道读取数据。我删除了 fork,并尝试在 Linux 上对其进行测试——该程序被挂起read(),等待管道上的数据。这是一个小型复制器:

#include <stdio.h>
#include <unistd.h>
const char in[7] = "qwerty";

int main ()
{
    int fds[2], stdout_sav;
    char str[8] = {0};
    pipe(fds);
    if ((stdout_sav = dup(1)) < 0) return 1;  // save stdout
    if (dup2(fds[1], 1) < 0) return 2;   // stdout -> pipe
    close(fds[1]);

    if (printf(in) <= 0) return 3;
    //fsync(1);        // behavior does not change if I add a fsync here
    read(fds[0], str, sizeof(in));    // HERE: read waits for data
    close(fds[0]);
    if (dup2(stdout_sav, 1) < 0) return 4;   // restore stdout
    close(stdout_sav);

    printf("Received %s\n", str);
    return 0;
}

由于它在 Linux 上不起作用,我认为代码中存在错误的逻辑,但我认为它没有任何问题。

我有一个想法,如果没有阅读器,单个进程将不会写入管道,但是,这不是真的,因为以下代码可以正常工作:

    pipe(fds);
    write(fds[1], in, sizeof(in));
    close(fds[1]);
    read(fds[0], str, sizeof(in));
    close(fds[0]);
    printf("Received %s\n", str);

标签: cpipestdoutdup

解决方案


您似乎忘记了当连接到管道时stdout完全缓冲的。

您需要显式刷新stdout才能将数据实际写入管道。由于没有刷新数据,因此管道中没有要读取的内容,并且read调用阻塞。

所以printf打电话后你需要fflush(stdout)


推荐阅读