Unable to understand behavior of pipe - Unix

This is a discussion on Unable to understand behavior of pipe - Unix ; #include 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]); /* ...

+ Reply to Thread
Results 1 to 12 of 12

Thread: Unable to understand behavior of pipe

  1. Unable to understand behavior of pipe

    #include

    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!

  2. Re: Unable to understand behavior of pipe

    On Mar 21, 3:35 pm, Sanchit 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..??
    >
    > 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.

  3. Re: Unable to understand behavior of pipe

    On Mar 21, 6:35 am, Sanchit 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

  4. Re: Unable to understand behavior of pipe

    On Mar 21, 11:28 pm, David Schwartz wrote:
    > On Mar 21, 6:35 am, Sanchit 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


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

  5. Re: Unable to understand behavior of pipe

    On Mar 22, 2:17 am, Sanchit 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

  6. Re: Unable to understand behavior of pipe

    On Mar 22, 4:15 pm, David Schwartz wrote:
    > On Mar 22, 2:17 am, Sanchit 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


    Thanks.. But am confused 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


  7. Re: Unable to understand behavior of pipe

    On Mar 22, 4:32 am, Sanchit wrote:

    > Thanks.. But am confused 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

  8. Re: Unable to understand behavior of pipe

    On Mar 21, 1:35 pm, Sanchit wrote:
    > #include


    > 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.






  9. Re: Unable to understand behavior of pipe

    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!

  10. Re: Unable to understand behavior of pipe

    On Mar 22, 7:22 am, Sanchit 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

  11. Re: Unable to understand behavior of pipe

    On Mar 22, 7:27 pm, David Schwartz wrote:
    > On Mar 22, 7:22 am, Sanchit 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


    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!


  12. Re: Unable to understand behavior of pipe

    On Mar 22, 3:30 pm, Sanchit wrote:
    > On Mar 22, 7:27 pm, David Schwartz wrote:
    > > On Mar 22, 7:22 am, Sanchit 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

    >
    > 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?

+ Reply to Thread