如何清空协处理器管道中的I/O缓冲区

3
我正在使用 pipe 来编写一个 coprocess。父进程创建两个管道,一个用于向子进程写入,另一个用于从子进程读取。但当我运行程序时,它会挂起,因为将默认的 printf 设置为完全缓冲。而我不想在子进程源代码中使用 fflush 缓冲区。

我知道《UNIX环境高级编程》第19章介绍了一种使用伪终端的方法。但我想知道是否有更简单的方法来实现它。谢谢大家。

这是我的源代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>


int main()
{
    #define MAXSIZE 1024

    char workload[MAXSIZE];
    char result[MAXSIZE];
    char buf[10] = {0};
    workload[strlen(workload)] = EOF;
    int workload_size = strlen(workload);

    int fd1[2], fd2[2];
    int n;
    pid_t pid;
    if (pipe(fd1) < 0 || pipe(fd2) < 0) {
        fprintf(stderr, "pipe error: %s\n", strerror(errno));
        exit(1);
    }

    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork error: %s\n", strerror(errno));
        exit(1);
    } else if (pid > 0) {
        close(fd1[0]);
        close(fd2[1]);
        while(fgets(workload, MAXSIZE, stdin) != NULL)
        {
            workload_size = strlen(workload);
            if (write(fd1[1], workload, workload_size) != workload_size) {
                fprintf(stderr, "write to pipe error: %s\n", strerror(errno));
                exit(1);
            }

            if ((n = read(fd2[0], result, MAXSIZE)) < 0) {
                fprintf(stderr, "read from pipe error: %s\n", strerror(errno));
                exit(1);
            }

            if (n == 0) {
                fprintf(stderr, "child closed the pipe\n");
                exit(1);
            }

            result[n] = 0;

            if (puts(result) == EOF) {
                fprintf(stderr, "fputs error\n");
                exit(1);
            }
        }
    } else {
        close(fd1[1]);
        close(fd2[0]);
        if (fd1[0] != STDIN_FILENO) {
            if (dup2(fd1[0] ,STDIN_FILENO) != STDIN_FILENO) {
                fprintf(stderr, "dup2 error to stdin.\n");
                exit(1);
            }
            close(fd1[0]);
        }
        if (fd2[1] != STDOUT_FILENO) {
            if (dup2(fd2[1] ,STDOUT_FILENO) != STDOUT_FILENO) {
                fprintf(stderr, "dup2 error to stdout.\n");
                exit(1);
            }
            close(fd2[1]);
        }

        if (execl("./a.out", "a.out", NULL) < 0) {
            fprintf(stderr, "execl error: %s\n", strerror(errno));
            exit(1);
        }
        exit(0);
    }

    return 0;
}

子进程刚刚从标准输入中读取了内容,并将其输出:
#include <stdio.h>

int main()
{
    #define MAXSIZE 1024
    char x[MAXSIZE];
    int n;
    while(fgets(x, 1024, stdin) != NULL)
    {
        printf("%s", x);
    }
    return 0;
}
1个回答

2
你可以使用stdbuf实用程序来更改子进程的缓冲设置。
或者,如果你可以更改子进程的代码,可以直接从子进程中调用setvbuf

我想知道是否可以直接在源代码中更改管道的缓冲。 - Bin Wang
execl之前这样做是行不通的。setvbuf需要从子进程中调用。 - Maxim Egorushkin
如果我使用setvbuf来设置管道的缓冲区会怎样呢?我尝试使用fdopen将管道打开为流,但失败了:坏文件描述符。在父进程中设置它是否可能? - Bin Wang
setvbuf 只影响 FILE 结构,而不影响文件描述符/描述。 - Maxim Egorushkin
fdopen 可以返回一个 FILE 结构,我在 setvbuf 中使用了它。现在我知道这是错误的。我刚刚谷歌了一下,认为在父进程中没有简单的方法来做到这一点。 - Bin Wang
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接