Welcome to a comprehensive guide on C Programming's Inter-Process Communication (IPC)! In this lesson, we'll delve into the world of communicating between multiple processes in a system, exploring different methods and practical applications. Let's get started!
IPC is a mechanism that allows multiple processes to share data, synchronize their actions, and coordinate resources in a multi-process system. In other words, IPC enables processes to communicate and collaborate with each other, even when they are running concurrently.
IPC plays a vital role in improving system efficiency and scalability by enabling processes to share resources and reduce redundant computations. For example, in a web server, IPC is essential for handling multiple client requests concurrently, improving responsiveness and throughput.
In C Programming, several IPC methods are available, each with its strengths and weaknesses. The most common ones are:
In this lesson, we'll focus on pipes and message queues, which are suitable for beginners and intermediate programmers.
A pipe is a simple form of IPC that allows two processes to communicate by reading and writing to a file descriptor. The pipe is unidirectional, meaning data can only flow in one direction.
To create a pipe in C, use the pipe() system call. Here's a simple example:
#include <stdio.h>
#include <unistd.h>
int main() {
int fd[2]; // file descriptor array
// Create pipe
if (pipe(fd) == -1) {
perror("Pipe creation failed");
return 1;
}
// Processes can now read from fd[0] and write to fd[1]
return 0;
}š Note: The pipe() function creates a pipe, returning file descriptors for the read and write ends.
To write to a pipe, use the write() function with the pipe's write file descriptor. To read from a pipe, use the read() function with the pipe's read file descriptor.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFER_SIZE 256
int main() {
int fd[2];
char buffer[BUFFER_SIZE];
// Create pipe
if (pipe(fd) == -1) {
perror("Pipe creation failed");
return 1;
}
pid_t child = fork();
if (child == -1) {
perror("Fork failed");
return 1;
}
if (child == 0) {
// Child process writes to the pipe
close(fd[0]); // Close read end
char message[] = "Hello from the child!";
write(fd[1], message, sizeof(message));
close(fd[1]); // Close write end
} else {
// Parent process reads from the pipe
close(fd[1]); // Close write end
ssize_t bytes_read = read(fd[0], buffer, sizeof(buffer));
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("Child said: %s\n", buffer);
}
close(fd[0]); // Close read end
}
return 0;
}š Note: The fork() system call creates a new process, called the child process. Both the parent and child processes can access the pipe.
Message queues are a more sophisticated IPC method that allows processes to send and receive messages of arbitrary size. Unlike pipes, message queues are bidirectional, and multiple processes can read and write to the same queue.
To create a message queue in C, use the msgget() system call.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSG_KEY 123456
int main() {
int msgid = msgget(MSG_KEY, IPC_CREAT | 0666);
if (msgid == -1) {
perror("Message queue creation failed");
return 1;
}
// Message queue created or found
return 0;
}š Note: The msgget() function creates or opens an existing message queue with the specified key.
To send a message to a message queue, use the msgsnd() function. To receive a message from a message queue, use the msgrcv() function.
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_t {
long mtype;
char mtext[256];
};
#define MSG_KEY 123456
#define MSG_SIZE sizeof(struct msg_t)
int main() {
int msgid = msgget(MSG_KEY, 0);
if (msgid == -1) {
perror("Message queue creation failed");
return 1;
}
pid_t child = fork();
if (child == -1) {
perror("Fork failed");
return 1;
}
if (child == 0) {
// Child process sends a message to the queue
struct msg_t msg;
strcpy(msg.mtext, "Hello from the child!");
msg.mtype = 1;
if (msgsnd(msgid, &msg, MSG_SIZE, 0) == -1) {
perror("Message sending failed");
return 1;
}
} else {
// Parent process receives a message from the queue
struct msg_t received_msg;
if (msgrcv(msgid, &received_msg, MSG_SIZE, 1, 0) == -1) {
perror("Message receiving failed");
return 1;
}
printf("Child said: %s\n", received_msg.mtext);
}
return 0;
}š Note: The msgsnd() function sends a message to the specified message queue. The msgrcv() function receives a message from the specified message queue.
What is the purpose of Inter-Process Communication (IPC)?
What are the two primary IPC methods we've covered in this lesson?