STDIN,带有printf scanf挂起的STDOUT重定向

问题描述 投票:0回答:1

谁能找出为什么这段代码挂在父代的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;
}
c fork stdout stdin
1个回答
0
投票

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

因为您使stdout写入管道,所以它不再是行缓冲的,而是完全缓冲的。这意味着仅当您填满内部缓冲区或通过调用fflush(stdout)进行显式操作时,才会刷新输出。

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

您已经发现,解决方案是在子进程中写入stdout后显式刷新它。

© www.soinside.com 2019 - 2024. All rights reserved.