c - 使用 printf scanf 进行 STDIN、STDOUT 重定向挂起

标签 c fork stdout stdin

任何人都可以找出为什么此代码卡在父级的 fgets() 和子级的 scanf() 处吗?
如果我将子进程的 printf/scanf 转换为写入/读取,它不会挂起。
谁能给出这个问题的原因吗?

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 的输出是行缓冲的,这意味着当您打印换行符时,stdout 内部缓冲区将被刷新('\n')。 但是这只是当stdout连接到终端或控制台时的默认设置。

由于您将stdout写入管道,它不再是行缓冲的,而是完全缓冲的。这意味着只有当您填满内部缓冲区时,或者通过调用 fflush(stdout) 显式执行操作时,输出才会被刷新。

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

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

关于c - 使用 printf scanf 进行 STDIN、STDOUT 重定向挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59016862/

相关文章:

python - 最多等待 N 秒,让 fork 的子 PID 完成

"fork()"生成的子进程的进程 ID 是否可以小于其父进程?

docker - 如何将 docker cron 日志写入 stdout/stderr

c - 用指针复制数据结构

C 如何在变量输入中使用结构体和 malloc

c - C中的堆栈变量混淆

c - fork 执行顺序

具有可编辑默认值的 Windows Perl 行编辑器?

linux - 从进程读取标准输出(Linux 嵌入式)

从宏调用中调用宏