Individual Assignment
Individual Assignment
parent to child processes using pipes, allows the parent to enter a message, and displays the
message in child processes is a complex task. #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_CHILDREN 3
#define MESSAGE_SIZE 100
int main() {
signal(SIGINT, interruptHandler); // Register interrupt handler
if (child_pid == -1) {
perror("Fork failed");
exit(1);
} else if (child_pid == 0) {
// Child process
close(pipes[i][1]); // Close the write end of the pipe
char message[MESSAGE_SIZE];
int bytes_read = read(pipes[i][0], message, MESSAGE_SIZE);
if (bytes_read > 0) {
message[bytes_read] = '\0';
printf("Child %d received message: %s", i, message);
} else {
printf("Child %d received no message.\n", i);
}
char message[MESSAGE_SIZE];
printf("Enter a message for Child %d: ", i);
fgets(message, MESSAGE_SIZE, stdin);
write(pipes[i][1], message, strlen(message) + 1);
return 0;
}
This program creates multiple child processes, sets up pipes for inter-process communication,
allows the parent to enter a message for each child, and displays the messages in the child
processes. It also handles Ctrl+C interrupts gracefully. Note that the number of child processes
can be controlled by changing the `num_children` variable.
Codes Explanation
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
```
These are the necessary header files included in the code for standard input/output, memory
allocation, process management, and signal handling.
```c
#define MAX_CHILDREN 3
#define MESSAGE_SIZE 100
```
These are constant definitions used in the code. `MAX_CHILDREN` specifies the maximum
number of child processes, and `MESSAGE_SIZE` sets the maximum size for messages
passed between the parent and child processes.
```c
int pipes[MAX_CHILDREN][2]; // Array to hold pipe file descriptors
pid_t child_pids[MAX_CHILDREN];
```
Here, we declare an array to hold file descriptors for pipes, which are used for communication
between parent and child processes. `child_pids` is an array to store the process IDs of the
child processes.
```c
void interruptHandler(int signal) {
printf("\nCtrl+C interrupt detected. Program terminated.\n");
for (int i = 0; i < MAX_CHILDREN; i++) {
if (child_pids[i] > 0) {
kill(child_pids[i], SIGTERM);
}
}
exit(0);
}
```
This function `interruptHandler` is a signal handler for the Ctrl+C (SIGINT) interrupt signal. It
prints a message and gracefully terminates the program, ensuring that child processes are also
terminated.
```c
int main() {
signal(SIGINT, interruptHandler); // Register interrupt handler
```
In the `main` function, we register the `interruptHandler` function to handle the Ctrl+C signal.
```c
for (int i = 0; i < MAX_CHILDREN; i++) {
if (pipe(pipes[i]) == -1) {
perror("Pipe creation failed");
exit(1);
}
```
This loop creates a set of pipes for inter-process communication. If pipe creation fails, an error
message is printed, and the program exits.
```c
pid_t child_pid = fork();
if (child_pid == -1) {
perror("Fork failed");
exit(1);
} else if (child_pid == 0) {
```
Here, we use `fork` to create child processes. If `fork` fails, an error message is printed, and the
program exits. If `fork` succeeds, the code inside the `if (child_pid == 0)` block runs, indicating
that this section is executed only by child processes.
```c
close(pipes[i][1]); // Close the write end of the pipe
char message[MESSAGE_SIZE];
int bytes_read = read(pipes[i][0], message, MESSAGE_SIZE);
if (bytes_read > 0) {
message[bytes_read] = '\0';
printf("Child %d received message: %s", i, message);
} else {
printf("Child %d received no message.\n", i);
}
This code is executed by the child processes. It closes the write end of the pipe, reads a
message from the pipe, and prints the received message. It then closes the read end of the pipe
and exits.
```c
child_pids[i] = child_pid; // Store child process IDs
close(pipes[i][0]); // Close the read end of the pipe
char message[MESSAGE_SIZE];
printf("Enter a message for Child %d: ", i);
fgets(message, MESSAGE_SIZE, stdin);
write(pipes[i][1], message, strlen(message) + 1);
This section is executed by the parent process. It stores the child process IDs, closes the read
end of the pipe, allows the user to enter a message, writes the message to the pipe, and closes
the write end of the pipe.
```c
for (int i = 0; i < MAX_CHILDREN; i++) {
wait(NULL);
}
```
Finally, the parent process waits for all child processes to finish before exiting.