For Programmers: Free Programming Magazines  


Home > Archive > Unix Programming > March 2008 > Unable to understand behavior of pipe









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Unable to understand behavior of pipe
Sanchit

2008-03-21, 7:19 pm

#include <stdio.h>

main()
{
int fd[2];

pipe(fd); /* a pipe is created: fd[0] for read; fd[1] for write
*/

if (fork() == 0) { /* 1st child - output redirection */
dup2(fd[1], 1); /* connect stdout to pipe */
close(fd[0]); /* close unneeded file descriptors */
close(fd[1]);
printf("\nThis is the write end of the pipe:\n");
fflush(stdout); /* write out the msg to terminal */
execl("/usr/bin/who", "who", (char *)0);
printf("\nDummy Text Line\n");
}

if (fork() == 0) { /* 2nd child - input redirection */
dup2(fd[0], 0); /* connect stdin to pipe */
close(fd[0]); /* close unneeded file descriptors */
close(fd[1]);
printf("\nThis is the read end of the pipe:\n");
execl("/bin/sort", "sort", (char *)0);
printf("\nDummy Text Line\n");
}

close(fd[0]); /* parent is taking it easy */
close(fd[1]);
printf("\nParent is terminating\n");
return(0);


/////


I am unable to understand
dup2(fd[1], 1); /* connect stdout to pipe */
close(fd[0]); /* close unneeded file descriptors */
close(fd[1]);

now when we are duplication fd[1] to stdout.... Then if we will close
it then what will happen..??

And what will be expected ouput!
vippstar@gmail.com

2008-03-21, 7:19 pm

On Mar 21, 3:35 pm, Sanchit <sanchitgupt...@gmail.com> wrote:
> <snip c code>
> /////
>
> I am unable to understand
> dup2(fd[1], 1); /* connect stdout to pipe */
> close(fd[0]); /* close unneeded file descriptors */
> close(fd[1]);
>
> now when we are duplication fd[1] to stdout.... Then if we will close
> it then what will happen..??
>
> And what will be expected ouput!


When pipe is called, two anonymous files are created. One for reading
and one for writing.
The file descriptor fd[0] is for reading and fd[1] for writing.
Everytime a dup() or a fork() is called, the descriptors are
duplicated, however there are still only *2* files.
A file ceases to be open when all descriptors (references) of it are
closed().
Just closing a reference, I presume, only deallocates the entry in the
process fd table.

child fd[0] fd[1]
child fd[0] fd[1]
parent fd[0] fd[1]
.------------.
| out | in |
'------------'

Here you have a parent and two child processes. They both have the
same two files open, one for reading and one for writing.
The parent serves only to open the files and to fork() the children.
David Schwartz

2008-03-21, 7:19 pm

On Mar 21, 6:35 am, Sanchit <sanchitgupt...@gmail.com> wrote:

> I am unable to understand
> dup2(fd[1], 1); /* connect stdout to pipe */
> close(fd[0]); /* close unneeded file descriptors */
> close(fd[1]);


> now when we are duplication fd[1] to stdout.... Then if we will close
> it then what will happen..??


After the duplication, there are two file handles that refer to the
same end of the same pipe. Then one of them is closed, leaving just
one. The pipe itself will be destroyed when there are no references
left to it.

DS
Sanchit

2008-03-22, 4:30 am

On Mar 21, 11:28 pm, David Schwartz <dav...@webmaster.com> wrote:
> On Mar 21, 6:35 am, Sanchit <sanchitgupt...@gmail.com> wrote:
>
>
> After the duplication, there are two file handles that refer to the
> same end of the same pipe. Then one of them is closed, leaving just
> one. The pipe itself will be destroyed when there are no references
> left to it.
>
> DS


SO what will be expected output? Also here will buffering of printf
will come in picture??
David Schwartz

2008-03-22, 8:11 am

On Mar 22, 2:17 am, Sanchit <sanchitgupt...@gmail.com> wrote:

> SO what will be expected output?


The output of 'who' will pass to the input of 'sort' through the pipe.
The pipe will go away when both processes terminate. The output of
'sort' will be left where it is.

> Also here will buffering of printf
> will come in picture??


That's a matter of the internal details of 'sort' and 'who'. These
programs don't need to know or care that they're talking to a pipe.
When 'who' terminates, its end of the pipe will close, causing 'sort'
to read end-of-file.

DS
Sanchit

2008-03-22, 8:11 am

On Mar 22, 4:15 pm, David Schwartz <dav...@webmaster.com> wrote:
> On Mar 22, 2:17 am, Sanchit <sanchitgupt...@gmail.com> wrote:
>
>
> The output of 'who' will pass to the input of 'sort' through the pipe.
> The pipe will go away when both processes terminate. The output of
> 'sort' will be left where it is.
>
>
> That's a matter of the internal details of 'sort' and 'who'. These
> programs don't need to know or care that they're talking to a pipe.
> When 'who' terminates, its end of the pipe will close, causing 'sort'
> to read end-of-file.
>
> DS


Thanks.. But am about following points.

1. We are duplicating fd[1] to stdout. So now whatever will be written
on stdout.. will go to pipe??? Now if this happens all the statements
which will get printed on screen should be input to sort thus all the
statements should be sorted not only output of who.

2. If second child (the one which involves sort) is called first ..
then there will be no input to it. Then what will happen

--Sanchit

David Schwartz

2008-03-22, 8:11 am

On Mar 22, 4:32 am, Sanchit <sanchitgupt...@gmail.com> wrote:

> Thanks.. But am about following points.


> 1. We are duplicating fd[1] to stdout. So now whatever will be written
> on stdout.. will go to pipe???


When the new process writes on its file descriptor 1, it will be
writing to the pipe. File descriptor 1 now refers to the 'write' side
of the pipe.

> Now if this happens all the statements
> which will get printed on screen should be input to sort thus all the
> statements should be sorted not only output of who.


Huh? No. The old file descriptor 1 is implicitly closed by the 'dup'
operation and is replaced with a new descriptor that refers to the
write side of the pipe. The old stdout is completely unaffected by
this, other than that it loses a reference.

> 2. If second child (the one which involves sort) is called first ..
> then there will be no input to it. Then what will happen


Type 'sort' at a shell prompt and what happens? The 'sort' program
starts, and waits for input. The parent still has a reference to the
other end of the pipe, so 'sort' will wait for something to write to
it.

The 'sort' command will keep reading input, waiting if necessary,
until it gets an end-of-file or an error.

DS
William Pursell

2008-03-22, 7:13 pm

On Mar 21, 1:35 pm, Sanchit <sanchitgupt...@gmail.com> wrote:
> #include <stdio.h>


> main()
> {
> int fd[2];
>
> pipe(fd); /* a pipe is created: fd[0] for read; fd[1] for write */


You MUST check that pipe succeeded before continuing.
Checking error conditions is important, and I believe it
is an error in execl later that is causing your confusion.

>
> if (fork() == 0) { /* 1st child - output redirection */
> dup2(fd[1], 1); /* connect stdout to pipe */


Technically, this does not connect stdout to the pipe. Instead,
it closes the file descriptor underlying stdout, and then creates
a new file descriptor with the same value as the file descriptor
underlying stdout. It is generally a bad idea to manipulate
the file descriptors underlying a FILE *.

> close(fd[0]); /* close unneeded file descriptors */
> close(fd[1]);
> printf("\nThis is the write end of the pipe:\n");
> fflush(stdout); /* write out the msg to terminal */


This comment is wrong, and I believe gets to the
heart of your confusion. At this point, stdout has
absolutely nothing to do with a terminal. When you
called dup2, the file descriptor underlying stdout
was changed. STDOUT_FILENO now references
the write end of the pipe, and that pipe is NOT
a terminal. (You really should fclose(stdout)
before you call dup2, and not use stdout anymore.)

> execl("/usr/bin/who", "who", (char *)0);
> printf("\nDummy Text Line\n");


You do realize that this line should never be called
unless execl fails, right?

> }
>
> if (fork() == 0) { /* 2nd child - input redirection */
> dup2(fd[0], 0); /* connect stdin to pipe */
> close(fd[0]); /* close unneeded file descriptors */
> close(fd[1]);
> printf("\nThis is the read end of the pipe:\n");
> execl("/bin/sort", "sort", (char *)0);
> printf("\nDummy Text Line\n");


On my system, this printf is called. Which means that execl()
failed. For me, it failed because /bin/sort does not exist.
Presumably, you meant to invoke "/usr/bin/sort". There
are 2 things that could be changed here.
1) use execlp( "sort", ... ) instead of execl
2) Replace the dummy printf call with:
perror( "execl" ); _exit( EXIT_FAILURE );

My guess is that replacing /bin/sort with the correct
path may give you the output you want/expect.





Sanchit

2008-03-22, 7:13 pm

Thanks David and Williams for your excellent explanation. But still i
have one doubt. This may be related to printf which is involved in
program.

According to david

"At this point, stdout has
absolutely nothing to do with a terminal. When you
called dup2, the file descriptor underlying stdout
was changed. STDOUT_FILENO now references
the write end of the pipe, and that pipe is NOT
a terminal. "

Then this means whatever is written on stdout goes to pipe?
If yes then printf output should go to stdout...

And when you say STDOUT_FILENO references to write end of pipe does
these means that whatever we write to stdout will go to pipe!
David Schwartz

2008-03-22, 7:13 pm

On Mar 22, 7:22 am, Sanchit <sanchitgupt...@gmail.com> wrote:

> "At this point, stdout has
> absolutely nothing to do with a terminal. When you
> called dup2, the file descriptor underlying stdout
> was changed. STDOUT_FILENO now references
> the write end of the pipe, and that pipe is NOT
> a terminal. "


> Then this means whatever is written on stdout goes to pipe?


Yes, if written by the process that performed the redirect. Other
processes are not affected.

> If yes then printf output should go to stdout...


Correct.

> And when you say STDOUT_FILENO references to write end of pipe does
> these means that whatever we write to stdout will go to pipe!


Yes. Again, only for that process.

DS
Sanchit

2008-03-22, 7:13 pm

On Mar 22, 7:27 pm, David Schwartz <dav...@webmaster.com> wrote:
> On Mar 22, 7:22 am, Sanchit <sanchitgupt...@gmail.com> wrote:
>
>
> Yes, if written by the process that performed the redirect. Other
> processes are not affected.
>
>
> Correct.
>
>
> Yes. Again, only for that process.
>
> DS


Ok...

printf("\nThis is the write end of the pipe:\n");
fflush(stdout);

So now output of printf will not be printed on screen???
So there is no significance of printf here as the test will not be
flushed and it will not be passed to sort also!

William Pursell

2008-03-23, 4:43 am

On Mar 22, 3:30 pm, Sanchit <sanchitgupt...@gmail.com> wrote:
> On Mar 22, 7:27 pm, David Schwartz <dav...@webmaster.com> wrote:
>
>
>
>
>
>
>
>
> Ok...
>
> printf("\nThis is the write end of the pipe:\n");
> fflush(stdout);
>
> So now output of printf will not be printed on screen???
> So there is no significance of printf here as the test will not be
> flushed and it will not be passed to sort also!


The text "\nThis is the write end of the pipe:\n" will be
written into the pipe. Another process (your second
child, the one that attempts to invoke sort) reads
that text from the pipe. If the sort execs succesfully,
then sort will read that text and print it to its
stdout. Assuming you invoke the command
from a terminal and do not redirect it, that
process's stdout will be the terminal. However,
if sort does not exec succesfully, then your
program's 2nd child will print "\nDummy Text Line\n",
and never read from the pipe, so the message
from the first child is lost (no one ever reads it
from the pipe).

I'm not sure I understand your confusion exactly.
Are you running the program and seeing output
that you do not expect? What exactly is the output
you are getting, and why is it not what you expect.
When I run your original program, I get:


This is the read end of the pipe:

Dummy Text Line

Parent is terminating

Parent is terminating



The fact that "Dummy Text Line" is appearing indicates that
one of the execs failed. (It is the second one, that tries
to exec "/bin/sort" that is failing). The "Parent is terminating"
appears twice because it is printed by both the parent and
the 2nd child (the one that failed to exec "/bin/sort").
The message about the write end of the pipe is lost
when the pipe is destroyed. In other words, the output
I get is exactly what I expect. Is there something there
that you do not expect?
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com