Implementing Inter-Process Communication with Signals and Message Queues

Signal Handlign Examples

1. Capturing SIGINT

This program demonstrates capturing the SIGINT signal (Ctrl+C) with a custom handler.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void sigint_handler(int sig_num) {
    if (sig_num == SIGINT) {
        printf("Ctrl+C was pressed.\n");
    }
}

int main() {
    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("Failed to set signal handler");
        exit(EXIT_FAILURE);
    }

    while (1) {
        printf("Program is running...\n");
        sleep(2);
    }

    return 0;
}

2. Hanlding SIGCHLD to Prevent Zombie Processes

This example shows how to handle SIGCHLD signals to reap terminated child processes.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>

void child_handler(int sig_num) {
    if (sig_num == SIGCHLD) {
        while (waitpid(-1, NULL, WNOHANG) > 0);
    }
}

int main() {
    if (signal(SIGCHLD, child_handler) == SIG_ERR) {
        perror("Failed to set SIGCHLD handler");
        exit(EXIT_FAILURE);
    }

    for (int idx = 0; idx < 5; ++idx) {
        pid_t child_pid = fork();
        if (child_pid == 0) {
            sleep(1);
            exit(0);
        }
    }

    while (1) {
        pause();
    }

    return 0;
}

3. Using SIGALRM for Periodic Actions

This program uses SIGALRM to trigger periodic events, simulating a card game.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void alarm_handler(int sig_num) {
    if (sig_num == SIGALRM) {
        printf("A random card has been drawn.\n");
        alarm(3);
    }
}

int main() {
    if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
        perror("Failed to set alarm handler");
        exit(EXIT_FAILURE);
    }

    alarm(3);

    char user_input;
    while (1) {
        printf("Enter your card: ");
        scanf(" %c", &user_input);
        printf("You played: %c\n", user_input);
        alarm(3);
    }

    return 0;
}

4. Custom Signal Communication Between Processes

This example shows a child process sending a custom signal (SIGUSR1) to its parent.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

void custom_signal_handler(int sig_num) {
    if (sig_num == SIGUSR1) {
        printf("Received custom signal. Terminating.\n");
        raise(SIGTERM);
    }
}

int main() {
    if (signal(SIGUSR1, custom_signal_handler) == SIG_ERR) {
        perror("Failed to set custom signal handler");
        exit(EXIT_FAILURE);
    }

    pid_t process_id = fork();

    if (process_id > 0) {
        while (1) {
            printf("Parent process is alive.\n");
            sleep(1);
        }
    } else if (process_id == 0) {
        sleep(2);
        printf("Child process sending signal.\n");
        kill(getppid(), SIGUSR1);
        while (1) {
            printf("Child process continues.\n");
            sleep(1);
        }
    } else {
        perror("Fork failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Message Queue Communication

Basic Message Queue Implementation

This section demonstrates a simple client-server model using System V message queues.

Message Sender Program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

struct Message {
    long msg_type;
    char msg_content[256];
};

#define MSG_DATA_SIZE (sizeof(struct Message) - sizeof(long))

int main() {
    key_t queue_key = ftok("/tmp", 'A');
    if (queue_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0666);
    if (queue_id == -1) {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    struct Message outgoing_msg;

    while (1) {
        memset(outgoing_msg.msg_content, 0, sizeof(outgoing_msg.msg_content));
        printf("Enter message type: ");
        scanf("%ld", &outgoing_msg.msg_type);
        getchar();
        printf("Enter message text: ");
        fgets(outgoing_msg.msg_content, sizeof(outgoing_msg.msg_content), stdin);
        outgoing_msg.msg_content[strlen(outgoing_msg.msg_content) - 1] = '\0';

        if (msgsnd(queue_id, &outgoing_msg, MSG_DATA_SIZE, 0) == -1) {
            perror("msgsnd failed");
            exit(EXIT_FAILURE);
        }
        printf("Message sent.\n");

        if (strcmp(outgoing_msg.msg_content, "exit") == 0) {
            break;
        }
    }

    return 0;
}

Message Receiver Program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

struct Message {
    long msg_type;
    char msg_content[256];
};

#define MSG_DATA_SIZE (sizeof(struct Message) - sizeof(long))

int main() {
    key_t queue_key = ftok("/tmp", 'A');
    if (queue_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0666);
    if (queue_id == -1) {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    struct Message incoming_msg;

    while (1) {
        memset(incoming_msg.msg_content, 0, sizeof(incoming_msg.msg_content));
        if (msgrcv(queue_id, &incoming_msg, MSG_DATA_SIZE, 1, 0) == -1) {
            perror("msgrcv failed");
            exit(EXIT_FAILURE);
        }
        printf("Received: %s\n", incoming_msg.msg_content);

        if (strcmp(incoming_msg.msg_content, "exit") == 0) {
            break;
        }
    }

    if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
        perror("Failed to remove message queue");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Bidirectional Communication with Forked Processes

This example creates a bidirectional communication channel using a single message queue and forked processes.

Process A (Handles Type 1 Messages, Sends Type 2)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>

struct MessagePacket {
    long packet_type;
    char packet_data[256];
};

#define PACKET_SIZE (sizeof(struct MessagePacket) - sizeof(long))

int main() {
    key_t queue_key = ftok("/tmp", 'B');
    if (queue_key == -1) {
        perror("ftok error");
        exit(EXIT_FAILURE);
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0666);
    if (queue_id == -1) {
        perror("msgget error");
        exit(EXIT_FAILURE);
    }

    pid_t child_pid = fork();

    if (child_pid > 0) {
        struct MessagePacket send_packet;
        while (1) {
            memset(send_packet.packet_data, 0, sizeof(send_packet.packet_data));
            printf("Enter type for outgoing message: ");
            scanf("%ld", &send_packet.packet_type);
            getchar();
            printf("Enter message: ");
            fgets(send_packet.packet_data, sizeof(send_packet.packet_data), stdin);
            send_packet.packet_data[strlen(send_packet.packet_data) - 1] = '\0';

            if (msgsnd(queue_id, &send_packet, PACKET_SIZE, 0) == -1) {
                perror("msgsnd error");
                exit(EXIT_FAILURE);
            }
            printf("Message dispatched.\n");

            if (strcmp(send_packet.packet_data, "stop") == 0) {
                break;
            }
        }
        wait(NULL);
    } else if (child_pid == 0) {
        struct MessagePacket receive_packet;
        while (1) {
            memset(receive_packet.packet_data, 0, sizeof(receive_packet.packet_data));
            if (msgrcv(queue_id, &receive_packet, PACKET_SIZE, 2, 0) == -1) {
                perror("msgrcv error");
                exit(EXIT_FAILURE);
            }
            printf("Incoming message: %s\n", receive_packet.packet_data);

            if (strcmp(receive_packet.packet_data, "stop") == 0) {
                break;
            }
        }

        if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
            perror("msgctl error");
            exit(EXIT_FAILURE);
        }
        exit(EXIT_SUCCESS);
    } else {
        perror("fork error");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Process B (Handles Type 2 Messages, Sends Type 1)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>

struct MessagePacket {
    long packet_type;
    char packet_data[256];
};

#define PACKET_SIZE (sizeof(struct MessagePacket) - sizeof(long))

int main() {
    key_t queue_key = ftok("/tmp", 'B');
    if (queue_key == -1) {
        perror("ftok error");
        exit(EXIT_FAILURE);
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0666);
    if (queue_id == -1) {
        perror("msgget error");
        exit(EXIT_FAILURE);
    }

    pid_t child_pid = fork();

    if (child_pid > 0) {
        struct MessagePacket receive_packet;
        while (1) {
            memset(receive_packet.packet_data, 0, sizeof(receive_packet.packet_data));
            if (msgrcv(queue_id, &receive_packet, PACKET_SIZE, 1, 0) == -1) {
                perror("msgrcv error");
                exit(EXIT_FAILURE);
            }
            printf("Received: %s\n", receive_packet.packet_data);

            if (strcmp(receive_packet.packet_data, "stop") == 0) {
                break;
            }
        }
        wait(NULL);
    } else if (child_pid == 0) {
        struct MessagePacket send_packet;
        while (1) {
            memset(send_packet.packet_data, 0, sizeof(send_packet.packet_data));
            printf("Enter type for response: ");
            scanf("%ld", &send_packet.packet_type);
            getchar();
            printf("Enter response: ");
            fgets(send_packet.packet_data, sizeof(send_packet.packet_data), stdin);
            send_packet.packet_data[strlen(send_packet.packet_data) - 1] = '\0';

            if (msgsnd(queue_id, &send_packet, PACKET_SIZE, 0) == -1) {
                perror("msgsnd error");
                exit(EXIT_FAILURE);
            }
            printf("Response sent.\n");

            if (strcmp(send_packet.packet_data, "stop") == 0) {
                break;
            }
        }
        exit(EXIT_SUCCESS);
    } else {
        perror("fork error");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Tags: Linux c-programming signals message-queues IPC

Posted on Sun, 10 May 2026 01:47:56 +0000 by UrbanCondor