Advanced IPC Practice: Message Queues and Shared Memory with Forked Processes

  1. Message Queue: Independent Sender and Receiver This example demonstrates a basic message queue system where two separate processes — one acting as sender and the other as receiver — communicate via System V message queues.

Sender Implementation

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

#define MAX_TEXT_LEN 200

typedef struct {
    long type;
    char body[MAX_TEXT_LEN];
} Message;

#define MESSAGE_SIZE (sizeof(Message) - sizeof(long))

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

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

    Message msg = {0};
    while (1) {
        printf("Enter message type: ");
        if (scanf("%ld", &msg.type) != 1) break;
        while (getchar() != '\n'); // flush input buffer

        printf("Enter message content: ");
        if (fgets(msg.body, MESSAGE_SIZE, stdin) == NULL) break;

        if (msgsnd(qid, &msg, MESSAGE_SIZE, 0) == -1) {
            perror("msgsnd failed");
            break;
        }

        if (strncmp(msg.body, "quit", 4) == 0) break;
    }

    if (msgctl(qid, IPC_RMID, NULL) == -1) {
        perror("msgctl IPC_RMID failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Receiver Implementation

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

#define MAX_TEXT_LEN 200

typedef struct {
    long type;
    char body[MAX_TEXT_LEN];
} Message;

#define MESSAGE_SIZE (sizeof(Message) - sizeof(long))

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

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

    Message msg = {0};
    while (1) {
        ssize_t read_size = msgrcv(qid, &msg, MESSAGE_SIZE, 0, 0);
        if (read_size == -1) {
            perror("msgrcv failed");
            break;
        }
        printf("%s", msg.body);

        if (strncmp(msg.body, "quit", 4) == 0) break;
    }

    return 0;
}
  1. Shared Memory: Producer and Consumer This section shows how two independent processes may share a region of memory for data exchange using System V shared memory segments.

Producer (Writing Process)

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

#define BUF_SIZE 4096

int main() {
    const key_t shm_key = ftok("./", 'M');
    if (shm_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    const int segment_id = shmget(shm_key, BUF_SIZE, IPC_CREAT | 0666);
    if (segment_id == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    char *addr = shmat(segment_id, NULL, 0);
    if (addr == (void *)-1) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    char buffer[BUF_SIZE];
    while (1) {
        printf("Enter data for shared memory: ");
        if (fgets(buffer, sizeof(buffer), stdin) == NULL) break;

        strncpy(addr, buffer, BUF_SIZE - 1);
        addr[BUF_SIZE - 1] = '\0';

        if (strncmp(addr, "quit", 4) == 0) break;
    }

    if (shmdt(addr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    if (shmctl(segment_id, IPC_RMID, NULL) == -1) {
        perror("shmctl IPC_RMID failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Consumer (Reading Process)

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

#define BUF_SIZE 4096

int main() {
    const key_t shm_key = ftok("./", 'M');
    if (shm_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    const int segment_id = shmget(shm_key, BUF_SIZE, IPC_CREAT | 0666);
    if (segment_id == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    char *addr = shmat(segment_id, NULL, 0);
    if (addr == (void *)-1) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    while (1) {
        printf("Received: %s", addr);
        if (strncmp(addr, "quit", 4) == 0) break;
        sleep(1); // simulate polling delay
    }

    if (shmdt(addr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}
  1. Inter-Process Communication Using Forked Pairs with Separate Queues Here, two programs each spawn a parent and child process. Parent and child use different message queues to enable bidirectional communication:

Program A:

Parent sends to Queue 'Q', child reads from Queue 'R'

Program B:

Parent sends to Queue 'R', child reads from Queue 'Q'

Program A

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

#define MSG_SIZE 200

typedef struct {
    long type;
    char body[MSG_SIZE];
} Message;

#define BODY_SIZE (sizeof(Message) - sizeof(long))

int main() {
    const key_t send_key = ftok("./", 'Q');
    const key_t recv_key = ftok("./", 'R');

    if (send_key == -1 || recv_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    const int send_qid = msgget(send_key, IPC_CREAT | 0666);
    const int recv_qid = msgget(recv_key, IPC_CREAT | 0666);

    if (send_qid == -1 || recv_qid == -1) {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid > 0) { // Parent: send via send_qid
        Message msg = {0};
        while (1) {
            printf("Parent: Enter type & message: ");
            if (scanf("%ld", &msg.type) != 1) break;
            while (getchar() != '\n');
            if (fgets(msg.body, BODY_SIZE, stdin) == NULL) break;
            if (msgsnd(send_qid, &msg, BODY_SIZE, 0) == -1) {
                perror("msgsnd failed");
                break;
            }
            if (strncmp(msg.body, "quit", 4) == 0) break;
        }
        wait(NULL);
    }
    else if (pid == 0) { // Child: receive on recv_qid
        Message msg = {0};
        while (1) {
            if (msgrcv(recv_qid, &msg, BODY_SIZE, 0, 0) == -1) {
                perror("msgrcv failed");
                break;
            }
            printf("Child received: %s", msg.body);
            if (strncmp(msg.body, "quit", 4) == 0) break;
        }
    }

    return 0;
}

Program B

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

#define MSG_SIZE 200

typedef struct {
    long type;
    char body[MSG_SIZE];
} Message;

#define BODY_SIZE (sizeof(Message) - sizeof(long))

int main() {
    const key_t send_key = ftok("./", 'R');
    const key_t recv_key = ftok("./", 'Q');

    if (send_key == -1 || recv_key == -1) {
        perror("ftok failed");
        exit(EXIT_FAILURE);
    }

    const int send_qid = msgget(send_key, IPC_CREAT | 0666);
    const int recv_qid = msgget(recv_key, IPC_CREAT | 0666);

    if (send_qid == -1 || recv_qid == -1) {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid > 0) { // Parent: send via send_qid (R)
        Message msg = {0};
        while (1) {
            printf("Parent: Enter type & message: ");
            if (scanf("%ld", &msg.type) != 1) break;
            while (getchar() != '\n');
            if (fgets(msg.body, BODY_SIZE, stdin) == NULL) break;
            if (msgsnd(send_qid, &msg, BODY_SIZE, 0) == -1) {
                perror("msgsnd failed");
                break;
            }
            if (strncmp(msg.body, "quit", 4) == 0) break;
        }
        wait(NULL);
    }
    else if (pid == 0) { // Child: receive on recv_qid (Q)
        Message msg = {0};
        while (1) {
            if (msgrcv(recv_qid, &msg, BODY_SIZE, 0, 0) == -1) {
                perror("msgrcv failed");
                break;
            }
            printf("Child received: %s", msg.body);
            if (strncmp(msg.body, "quit", 4) == 0) break;
        }
    }

    return 0;
}

Thẻ: SystemV ipc message-queues shared-memory ftok

Đăng vào ngày 31 tháng 5 lúc 05:11