The code below forks a child process, and redirects stdout to the pipe. The child is supposed to read from the pipe but it's not happening. Strangely, if the parent is made to call printf at least once before calling dup2, things seem to work. I guess that's a luck not to be relied upon... but an explanation would be still great. More importantly, why is the child not able to read?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int fd[2];
pid_t p;
if(pipe(fd) == -1)
return -1;
if((p=fork()) == -1)
return -1;
if(p==0){
close(fd[1]);
dup2(fd[0],0);
fprintf(stderr,"Child starts\n");
int x;
scanf("%d",&x); // GETS STUCK HERE
fprintf(stderr,"Child ends\n");
exit(0);
}
// printf(" "); // THIS PRINTF SEEMS TO RESOLVE THE ISSUE?!
close(fd[0]);
dup2(fd[1],1);
printf("3\n");
fprintf(stderr, "Parent waiting\n");
wait(0);
fprintf(stderr, "Parent ends\n");
}
Lots of questions have been asked on fork
and pipe
but I could not find an answer to my problem. Apologies if it is a duplicate question.
CodePudding user response:
Parent stdout
is not line buffered (because it becomes a pipe). So, the data that printf("3\n");
outputs stays in the stream's buffer and is not flushed to the pipe.
There are two ways to fix this (in the parent):
- add
setlinebuf(stdout);
immediately before thatprintf
- add
fflush(stdout);
immediately after thatprintf
UPDATE:
And adding the extra printf() fixes it why? I suppose that at that point, the underlying file descriptor for standard output is still a terminal so it puts the stream into line-buffered mode, and that doesn't change when the underlying file descriptor is changed to a pipe. – Jonathan Leffler
Yes, that is correct. If we change:
printf(" ");
Into:
setlinebuf(stdout);
Then, that also works.
(i.e.) the printf
to a real tty [implicitly] set line buffered mode.
The probe/test for output is a tty device is [obviously] deferred until something active is done with the device (e.g. printf
)
The dup2
is transparent to the stream so the stream's flags stay the same.