Understanding pipes in C

So, for my class in Parallel Programming, recently I had to use pipes to coordinate multiple forked processes in C. While perhaps it isn’t even practical to do this anymore with things like OpenMP and other multiprocess libraries, we had to do it nonetheless. So, what are pipes in C? According the linux docs, pipes are essentially file descriptors which allow communication (one way) from multiple forked processes. So what happens when you create a pipe? Typically, you do something like:

int omgPipe[2];
if (pipe(omgPipe)){
    fprintf (stderr, "Pipe failed. Noooooooo.\n");
    return EXIT_FAILURE;
}

Here, you are creating a pipe and initializing it. When you create the integer array, you are essentially making an array of two file descriptor identifiers. There are two because the 0 index gets initialized to the side of the pipe that is reading and 1 gets initialized to the side of the pipe that is writing. Note, that when you fork a process everything gets copied, but file descriptors still point to the same files, hence why they’re used in pipes. Pipes really go in one direction, so let’s create a couple of pipes to make bidirectional communcation and then fork this process!

int parentToChild[2];
int childToParent[2];
if (pipe(parentToChild) || pipe(childToParent)){
    fprintf (stderr, "Pipe failed. Noooooooo.\n");
    return EXIT_FAILURE;
}

pid_t pid; 
pid = fork();

if (pid == 0){
    // We can close the reading side of the child to parent pipe on the child process
    close(childToParent[0]);
    int n = 1;
    int temp;
    // wait till parent sends a message through the pipe
    read(parentToChild[0], &temp, sizeof(temp));
    // do cool child stuff here
    // message the parent when done
    write(childToParent[1], &n, sizeof(n));

}
else{
    // Close the reading side of the parent to child pipe on the parent process
    close(parentToChild[0]);
    int n = 5;
    write(parentToChild[1], &n, sizeof(n));
    // parent stuff here
    int temp;
    // wait till child sends message to parent
    read(childToParent[0], &temp, sizeof(temp));
}

You’ll notice here that we can actually close the reading side of the pipes on the different processes. That’s because you have a copy of the file descriptors per process, so to free them up you close the reading side that you’re not going to be using on that thread. Then to send messages between the processes you use the appropriate pipe (parent to child or child to parent) and write to it like you would write to a normal file.

And that’s pipes. Let me know if I made any dumb mistake, and I’ll fix it right away, but that should be pretty much it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: