Can anyone find out why this code hang at fgets() for parent and scanf() for child?
If I turn child process's printf/scanf into write/read it doesn't hang.
Can any one give a reason to this problem?
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;
}
Output to stdout
is by default line-buffered, meaning the stdout
internal buffer is flushed when you print a newline ('\n'
). But that is only the default, when stdout
is connected to a terminal or console.
Since you make stdout
write to a pipe, it's no longer line-buffered, but fully buffered. That means the output will only be flushed when you fill up the internal buffer, or when explicitly doing by calling fflush(stdout)
.
Since your code as shown in the question doesn't flush the buffers, nothing will ever be written, which means the parent process will wait forever on input from fp_r
which never comes. Since the parent process is locked, it will in turn not write to fp_w
and the reading in the child-process will then also be blocked.
The solution, as you have discovered, is to explicitly flush stdout
after writing to it in the child-process.