Pipe or Unnamed Pipe IPC

Let’s discuss how pipe IPC works with an example. Also, we will discuss the usage of pipe IPC, and its advantages and disadvantages.

Pipe IPC - Interprocess communication

– A pipe is also called an Unnamed pipe. Because there is no file name associated with the IPC file which is used to transfer data. There are two file descriptors created using which read and write can happen. One file descriptor is for reading and one is for writing. So, only unidirectional communication is supported.
– Let’s have a simple example. Created two processes using a fork. One is a child and another is a parent.

– int pipefd[2] is used to store two file descriptors. The pipe is the system call that takes an integer array of two as an argument. pipe manual page.

int pipe(int pipefd[2]);

– pipe system call creates a unidirectional data channel. Which is nothing but a special IPC file. Which has two ends, One is read and another is write.

  • pipefd[0] identifier for the reading(used for receiving data) end.
  • pipefd[1] identifier for the writing(used for sending data) end.

– A write system call is used to write to the Pipe IPC file. Click here to refer write system call manual page.
– A read system call is used to read from the Pipe IPC file. Click here to refer read system call manual page.

//Simple pipe IPC example.
//vim pipe.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
        int pipefd[2];                         //two ends of pipe, pipefd[0]-reader, pipefd[1]-writer
        
        /*pipe creation using pipe system call
         *if success returns 0
         *if fails returns -1*/
        if (pipe(pipefd) < 0)
        {
                /*perror prints failure message
                 *based on global errno variable*/
                perror("Pipe failed");
                
                //exit if pipe creation fails.
                exit(EXIT_FAILURE);
        }
       
        /*Creating process using fork
         *fork returns 0 in child process
         *fork returns child process id in parent process*/
        if(fork())  //Creating process using fork,
        {
                //This is the parent process.
                int n = 5;
                printf("In parent value of n is=%d\n", n);
                
               /*writing to the pipe using file descriptor,
                 *value of 'n' goes to the IPC*/
                write(pipefd[1], &n, sizeof(int));
        }
        else
        {
                //This is the child process.
                int v;

                /*reading from the pipe IPC,
                 *value read into the buffer v*/
                read(pipefd[0], &v,sizeof(int));
                printf("In child value of v is=%d\n", v);
        }
}

o/p:
In parent value of n is=5
In child value of v is=5

– As shown in the above example, the Parent is sending a value of ‘n’ to the child process. A child is reading that value from a pipe in buffer variable ‘v’.

– let’s introduce sleep of 5 seconds in the parent process where writing is happening.

//Simple pipe IPC example.
//vim pipe.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
        int p[2]; //two ends of pipe, p[0]-reader, p[1]-writer

        /*pipe creation using pipe system call
         *if success returns 0
         *if fails returns -1*/
        if (pipe(p) < 0)
        {
                /*perror prints failure message
                 *based on global errno variable*/
                perror("Pipe failed");
                //exit if pipe creation fails.
                exit(EXIT_FAILURE);
        }

        /*Creating process using fork
         *fork returns 0 in child process
         *fork returns child process id in parent process*/
        if(fork())  //Creating process using fork,
        {
                //This is the parent process.
                int n = 5;
                printf("In parent value of n is=%d\n", n);

                /*Parent is sleeping for 1sec*5 = second*/
                for (int itr = 0; itr < 5; itr++)
                {
                        sleep(1);
                        printf("In parent is sleeping\n");
                }
                /*writing to the pipe using file descriptor,
                 *value of 'n' goes to the IPC*/
                write(p[1], &n, sizeof(int));
        }
        else
        {
                //This is the child process.
                int v;

                /*reading in from the pipe IPC,
                 *value read into the buffer v*/
                read(p[0], &v,sizeof(int));
                printf("In child value of v is=%d\n", v);
        }
}

output:

In parent value of n is=5
In parent is sleeping
In parent is sleeping
In parent is sleeping
In parent is sleeping
In parent is sleeping
In child value of v is=5

– What did you observe in the above program and output?
– The parent was sleeping for 5 seconds and meanwhile child was blocked and did not execute.
– Once the parent was awoken and wrote to the IPC file then only child read has happened. Because, as the parent was sleeping and not writing anything to the pipe file, the Child was not able to read anything and it blocked at read system call.
– The conclusion is if the Pipe file is empty and nothing to read so read blocks, If the Pipe file is full then there is no space to write so write blocks.
– There are also mechanisms to make read and write non-blocking. One way is using fcntl system call with the O_NONBLOCK option.

1 thought on “Pipe or Unnamed Pipe IPC”

Leave a Comment