Inter-process Communication(IPC) with fork() and pipe() in C

Table of Contents

Introduction

What is Inter-process Communication (IPC)

Fork()

Pipe()

IPC Using fork() and pipe()

Other Approaches to IPC

Conclusion

Introduction

This guide will help you understand the usage and implementation of Inter-process Communication (IPC) in C Programming language. In C programming, the fork() and pipe() functions are commonly used for process creation and Inter-process Communication, respectively. Here’s an introduction to each and explanation of how they can be used together.

What is Inter-process Communication (IPC)

Inter-process Communication (IPC) is a crucial mechanism provided by the operating system that allows processes to communicate with each other. This communication could involve a process letting another process know that some event has occurred or the transferring of data between processes. A diagram that illustrates interprocess communication is as follows:

graph LR
A[Process 1] <-- IPC --> B[Process 2]
B-->A

Fork()

Pipe()

IPC Using fork() and pipe()

  1. Before calling fork(), the parent creates a pipe object by calling pipe().
  2. Next, it calls fork(). Now both the parent and the child can write/read data through the pipe. This may cause some chaos, we will have to make this a one-way communication.
    flowchart LR
    A[Parent]
    B[Child]
    A--fork-->B
    
    flowchart LR
    A[Parent]
    B[Child]
    C[Pipe]
    A--write-->C
    B--write-->C
    C--read-->B
    C--read-->A
    
  3. After fork(), the parent closes its copy of the read-only end and the child closes its copy of the write-only end.
    flowchart LR
    A[Parent]
    B[Child]
    C[Pipe]
    A--write-->C
    C--read-->B
    
  4. Now the parent can pass information to the child.

Note: To ensure pipe work properly, you should: Always be sure to close the end of pipe you aren’t concerned with.
If the parent wants to receive data from the child, it should close pipefds[1], and the child should close pipefds[0]. When processes finish reading or writting, close related file descriptors. Otherwise, there will be undesired synchronization problems.

Below is a simple example of IPC using pipes by creating a pipe and forking a child process.

# fd[0] gets the read end; pipeEnds[1] gets the write end.
int fd[2];

# create a pipe and fork a child process
pipe(fd);
int n = fork();

# child process
if (n == 0) {

  # close child writing end
  close(fd[1]);
  
  # Read some data from the pipe.
  char data[12];
  read(fd[0], data, 12);
  exit(EXIT_SUCCESS);
} 

# parent process
else {
  close(fd[0]);
  # Write some data to the pipe.
  write(fd[1], "Hi my child\n", 12);
  exit(EXIT_SUCCESS);
}

The parent process writes the string “Hi my child\n” to the write end of the pipe (fd[1]), and the child process reads 11 bytes of data from the read end of the pipe (fd[0]).

Other Approaches to IPC

While fork() and pipe() are very useful for IPC, it’s worth noting that other approaches to implement IPC exist. Here are some examples:

These alternatives cater to diverse communication needs, from lightweight signaling to high-throughput data exchange.

Conclusion

Understanding the roles of fork() and pipe() is foundational for implementing effective IPC strategies in C programming. Together, these functions empower developers to create and coordinate processes seamlessly. As programmers, this unlocks the potential to design robust, responsive, and efficient multi-process applications.

References