Interprocess Communication (IPC) refers to the mechanisms provided by the operating system that allow processes to communicate with each other, either within the same system or across different systems (in distributed environments). Since processes run independently in their own address spaces, they need a way to share data, synchronize their actions, or send messages to each other in order to perform coordinated tasks.
IPC is crucial for many applications, especially in multitasking environments where different processes might need to collaborate or share data. Various IPC mechanisms exist, each with its specific use cases, performance characteristics, and complexities.
IPC can be broadly classified into two types based on how communication occurs between processes:
In message passing, processes communicate by sending and receiving messages. These messages can be either synchronous or asynchronous.
Direct Communication:
send(receiver, message) and receive(sender, message).Indirect Communication:
Pipes: Unidirectional communication channel between two processes.
Sockets: A more complex form of message passing, often used for communication between processes over a network. Sockets support both stream-based (TCP) and datagram-based (UDP) communication.
Message Queues: Allow processes to exchange messages, which are stored in queues. The system handles synchronization and buffering, and the messages can be retrieved by processes in the order they were sent.
Shared memory allows two or more processes to share a region of memory. One process writes to the memory region, while others can read from it. This is typically much faster than message passing because it avoids the overhead of copying data between processes.
Semaphores: A semaphore is a signaling mechanism used to synchronize access to shared resources. It helps in managing mutual exclusion and synchronizing processes to avoid race conditions.
Mutexes (Mutual Exclusion Locks): Similar to semaphores but typically used in situations where only one process can enter a critical section of code at a time. A mutex provides a mechanism for locking and unlocking shared resources.
Condition Variables: These are used to allow processes to wait for a certain condition to be met before continuing execution. They are often used in conjunction with mutexes.
Memory Mapped Files: Shared memory can also be mapped to a file in memory, allowing multiple processes to access and modify the data as though it were part of their memory space.
There are several ways to implement IPC, each suited for different situations. Below are some of the most common mechanisms:
A pipe is a unidirectional communication channel used between two processes. Pipes are usually used for communication between related processes (parent-child). In Unix-like systems, the pipe() system call creates a pipe.
#include <stdio.h>
#include <unistd.h>
int main() {
int pipe_fd[2];
pipe(pipe_fd); // Create a pipe
pid_t pid = fork(); // Create a child process
if (pid == 0) {
// Child Process: Writes to the pipe
close(pipe_fd[0]);
write(pipe_fd[1], "Hello, Parent!", 15);
close(pipe_fd[1]);
} else {
// Parent Process: Reads from the pipe
close(pipe_fd[1]);
char buffer[20];
read(pipe_fd[0], buffer, sizeof(buffer));
printf("Received from child: %s\n", buffer);
close(pipe_fd[0]);
}
return 0;
}
A message queue allows processes to send and receive messages in a queue-like structure. It can store messages until the receiver retrieves them.
Message queues can be created and managed using system calls like msgget(), msgsnd(), and msgrcv() in Unix-like systems.
As mentioned earlier, shared memory enables processes to communicate by accessing a common memory space. This is one of the fastest IPC mechanisms, as it avoids the need to copy data between processes. However, it requires synchronization mechanisms to prevent conflicts and ensure data consistency.
In Unix-like systems, shmget() creates a shared memory segment, and shmat() attaches it to the process's address space. Synchronization is done using semaphores or mutexes.
Sockets provide a mechanism for IPC that allows processes to communicate over a network or within the same system. Sockets can be either stream sockets (TCP) or datagram sockets (UDP), and they provide bidirectional communication.
// Server code snippet using TCP sockets
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(sockfd, 5);
int client_sock = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
send(client_sock, "Hello, Client!", 14, 0);
// Client code snippet using TCP sockets
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
char buffer[1024];
recv(sockfd, buffer, sizeof(buffer), 0);
printf("Received from server: %s\n", buffer);
Choosing the appropriate IPC mechanism depends on various factors:
Interprocess communication (IPC) is crucial for modern operating systems, enabling processes to coordinate and communicate effectively. It provides various mechanisms like message passing, shared memory, pipes, sockets, and message queues, each suited for different scenarios. By understanding the strengths and weaknesses of these mechanisms, developers can choose the most efficient method for their applications' needs, ensuring better performance, synchronization, and resource management in multitasking environments.
Open this section to load past papers