C Fork and Pipe closing ends

2019-06-11 01:26发布

问题:

I am building an application that requires two way communication with a few child processes. My parent is like a query engine constantly reading words from stdin and passes it to each child process. The child processes perform their processing and writes back to the parent on their exclusive pipes.

This is theoretically how it should work however I am stuck on the implementation details. The first issue is do I create 2 pipes before forking the child? When I fork, I know the child is going to inherit the parent's set of file descriptors, does this mean that 4 pipes will be created or simple 2 pipes just duplicated. If they are being duplicated in the child then does this mean if I were to close a file descriptor in the child, it would also close the parent's?

My theory is the following and I simply need clarification and be put on the right track. This is untested code, I just wrote it to give you an idea of what I am thinking. Thanks, any help is appreciated.

int main(void){
    int fd[2][2]; //2 pipes for in/out

    //make the pipes
    pipe(fd[0]); //WRITING pipe
    pipe(fd[1]); //READING pipe

    if(fork() == 0){
        //child
        //close some ends
        close(fd[0][1]); //close the WRITING pipe write end
        close(fd[1][0]); //close the READING pipe read end

        //start the worker which will read from the WRITING pipe
        //and write back to the READING pipe
        start_worker(fd[0][0], fd[1][1]);
    }else{
        //parent
        //close the reading end of the WRITING pipe
        close(fd[0][0]);
        //close the writing end of the READING pipe
        close(fd[1][1]);
        //write data to the child down the WRITING pipe
        write(fd[0][1], "hello\n", 6);

        //read from the READING pipe 
        int nbytes;
        char word[MAX];
        while ((nbytes = read(fd[1][0], word, MAXWORD)) > 0){
            printf("Data from child is: %s\n", word);
        }
    }

}

回答1:

The pipe itself is not duplicated upon fork.

A single pipe is unidirectional, and has 2 descriptors - one for reading, one for writing. So in process A you close e.g. write descriptor, in process B you close read descriptor -> you have a pipe from B to A.

Closing a descriptor in one process doesn't affect the descriptor in another process. After forking each process has its own descriptor space, which is a copy of parent process descriptors. Here's an excerpt from fork() man page:

The child process shall have its own copy of the parent's file descriptors. Each of the child's file descriptors shall refer to the same open file description with the corresponding file descriptor of the parent.