使用 printf scanf 的 STDIN、STDOUT 重定向挂起

STDIN, STDOUT redirection with printf scanf hangs

谁能找出为什么这段代码挂在父类的 fgets() 和子类的 scanf() 处?
如果我将子进程的 printf/scanf 变成 write/read 它不会挂起。
任何人都可以给出这个问题的原因吗?

int main(){
    int pfd1[2], pfd2[2];
    pipe(pfd1); pipe(pfd2);

    if (fork() == 0){
        dup2(pfd1[1], STDOUT_FILENO);
        dup2(pfd2[0], STDIN_FILENO);
        close(pfd1[0]); close(pfd1[1]);
        close(pfd2[1]); close(pfd2[0]);
        char buf[] = "Hello world\n";
        int n;
        printf("%s", buf);
        fflush(stdin);
        scanf("%d", &n);
        fprintf(stderr, "get n = %d\n", n);
    }    
    else {
        char buf[128];
        FILE *fp_w = fdopen(pfd2[1], "w");
        FILE *fp_r = fdopen(pfd1[0], "r");
        fgets(buf, 128, fp_r);
        printf("%s", buf);
        fprintf(fp_w, "%d\n", 10);

    }

    return 0;
}

默认情况下,stdout 的输出是行缓冲的,这意味着当您打印换行符 ('\n') 时,stdout 内部缓冲区会被刷新。 但是 这只是默认设置,当 stdout 连接到终端或控制台时。

由于您stdout 写入管道,它不再是行缓冲的,而是完全 缓冲的。这意味着仅当您填满内部缓冲区或通过调用 fflush(stdout).

明确执行时,才会刷新输出

由于问题中显示的代码不会刷新缓冲区,因此永远不会写入任何内容,这意味着父进程将永远等待来自 fp_r 的输入,但永远不会出现。由于父进程被锁定,它不会写入 fp_w 并且子进程中的读取也将被阻止。

如您所见,解决方案是在子进程中写入后显式刷新 stdout