I am learning something about PIPE in Linux, but I met something I can't figure out. I was reading rozmichelle's blog http://www.rozmichelle.com/pipes-forks-dups/#pipelines. The code below is to sort three words that parent process passes on to child process by PIPE.
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2]; // an array that will hold two file descriptors
pipe(fds); // populates fds with two file descriptors
pid_t pid = fork(); // create child process that is a clone of the parent
if (pid == 0) { // if pid == 0, then this is the child process
dup2(fds[0], STDIN_FILENO); // fds[0] (the read end of pipe) donates its data to file descriptor 0
close(fds[0]); // file descriptor no longer needed in child since stdin is a copy
close(fds[1]); // file descriptor unused in child
char *argv[] = {(char *)"sort", NULL}; // create argument vector
if (execvp(argv[0], argv) < 0) exit(0); // run sort command (exit if something went wrong)
}
// if we reach here, we are in parent process
close(fds[0]); // file descriptor unused in parent
const char *words[] = {"pear", "peach", "apple"};
// write input to the writable file descriptor so it can be read in from child:
size_t numwords = sizeof(words)/sizeof(words[0]);
for (size_t i = 0; i < numwords; i ) {
dprintf(fds[1], "%s\n", words[i]);
}
// send EOF so child can continue (child blocks until all input has been processed):
close(fds[1]);
int status;
pid_t wpid = waitpid(pid, &status, 0); // wait for child to finish before exiting
return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
In the code above, the parent process uses dprintf
, but I wonder if we can redirect parent process' standard out to PIPE's in. So I tried to write the code below.
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2];
pipe(fds);
pid_t pid = fork();
if (pid == 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
char *argv[] = {(char *)"sort", NULL};
if (execvp(argv[0], argv) < 0) exit(0);
}
// if we reach here, we are in parent process
close(fds[0]);
const char *words[] = {"pear", "peach", "apple"};
// write input to the writable file descriptor so it can be read in from child:
size_t numwords = sizeof(words)/sizeof(words[0]);
dup2(fds[1],STDOUT_FILENO);//redirect stdout
close(fds[1]); //fds[1] is not used anymore
for (size_t i = 0; i < numwords; i ) {
printf("%s\n", words[i]);
}
close(STDOUT_FILENO);
int status;
pid_t wpid = waitpid(pid, &status, 0);
return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
After redrecting, I used printf
, which in my understanding will output to STDOUT. However, this code print nothing, while the first code print as below:
apple
peach
pear
I can't figure out why this happen, is there something I understand mistakely?
CodePudding user response:
According to man pages, dprintf is a POSIX extension, not a standard library function, so it is not equivalent in terms of portability.
As far as their implementation in GLIBC is concerned, both printf
and dprintf
call __vfprintf_internal
, but note that dprintf
does also this (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)
which suggests flushing the buffer after the write.
printf
, on the other hand, does not.
I'd try fiddling with buffering, i.e. setbuf
, fflush
or similar on the stdout and see if that helps.