7

Here is the code:

int main() {

    int fd[2];
    pipe(fd);
    int r = fork();
    if (r > 0) { //parent
        close(fd[0]);
        // do a bunch of things
    } else { //child
        close(fd[1]);
        // do a bunch of things
    return 0;
}

This is a piece of code where the parent writes to the pipe and child reads from the pipe. My question is: for the two close statements, what exactly are they closing? The parent and the child should share the same file, i.e. fd[0] and fd[1]. If fd[0] is closed in the parent, shouldn't it also be closed in child?

Josh Durham
  • 1,632
  • 1
  • 17
  • 28
Xufeng
  • 6,452
  • 8
  • 24
  • 30

3 Answers3

6

From http://linux.die.net/man/2/pipe pipe() creates a pipe which consists of two file descriptors which correspond with the two "ends" of the pipe, the read end and the write end. It's not really the same thing as a file. The kernel is reading data from the write end, buffering it for you, and transferring it it to the read end.

This should make it obvious why pipe() creates two file descriptors. The writer writes all the data it needs into the write fd and closes the fd. This also triggers an EOF to be sent. The reader would usually keep reading data until it encounters the EOF and closes its end. In this scenario, there's a period of time where the write fd is closed but data is still buffered in the pipe, waiting to be read out by the reader. It doesn't make sense to have a single fd, as you'll need another layer of coordination between the writer and reader processes, otherwise who will do the closing, and when?

congusbongus
  • 13,359
  • 7
  • 71
  • 99
  • So after fork, the pipe has 4 ends? – Xufeng Feb 26 '14 at 05:06
  • 1
    @Xufeng no, after the fork the pipe is shared between the parent and child processes. It is up to you to decide whether the parent uses the write end or read end and vice versa. – congusbongus Feb 26 '14 at 05:07
  • Do the parent and the child share the 2 ends? If so, why closing an end in one process doesn't affect the same end in the other process? Or close() doesn't really close the end, it just close the connection between the process to that end? – Xufeng Feb 26 '14 at 05:10
  • 3
    Both processes will have a different file descriptor table , so when you are closing the descriptor in one process it is removed from its corresponding file descriptor table. – prince Feb 26 '14 at 05:14
  • @Xufeng to elaborate on what prince said (who is correct), the pipe and its "ends" exist separately to the processes. You can do a similar thing with `fopen` and `fork`: the parent and child processes can, in principle, read and write to the same file, although this is potentially dangerous and something that you shouldn't ever need to do. – congusbongus Feb 26 '14 at 05:16
3

The pipe() call always returns an integer array where the first element of array is the read descriptor to read from pipe and second element is the write descriptor to write into the pipe. The pipes provide one way communication. If you close fd[0] in parent and also in child there is from nowhere you can read from the pipe, in the reverse case if you close fd[1] in both the processes you cannot write into pipe, So we close the read descriptor in one process so that the process can only write and the other process will close write descriptor which will enable the process to only read from pipe.

prince
  • 1,129
  • 1
  • 15
  • 38
0

Since you forked after creating a pipe, you now have two pipes to work with. You should in fact see a pipe like a one way only line of communication, by forking it you now have a two way line of communication. But still two different pipes, so in order to give a direction to the stream of information, you close ends accordingly.

Edit: ps: this point of view works very effectively when thinking about how a pipe (that connects just two processes) works. If you find yourself tinkering with multiple pipes, you need to adapt a little the concept that I exposed earlier, but it still fundamentally works. This should help

Pit
  • 11
  • 3