MST

星途 面试题库

面试题:C语言Linux消息队列的同步与异常处理

在C语言的Linux消息队列编程中,当多个进程同时访问消息队列时,可能会出现同步问题。请描述如何使用信号量来解决消息队列访问的同步问题,并且说明如果在发送或接收消息过程中出现错误(如队列已满、消息类型不匹配等),应该如何进行异常处理,给出相应的代码示例。
42.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

使用信号量解决消息队列访问同步问题

  1. 初始化信号量: 在使用信号量前,需要先创建并初始化信号量。例如,使用semget函数创建信号量集,然后使用semctl函数初始化信号量的值。

  2. 获取信号量: 在进程访问消息队列前,获取信号量。如果信号量的值为0,进程会阻塞等待信号量的值变为1。可以使用semop函数来获取信号量。

  3. 释放信号量: 在进程完成对消息队列的访问后,释放信号量,将信号量的值加1,允许其他进程获取信号量并访问消息队列。同样使用semop函数来释放信号量。

异常处理

  1. 队列已满: 当发送消息时,如果消息队列已满,msgsnd函数会返回-1,并且errno被设置为EAGAINENOMEM。此时,可以选择等待一段时间后重试发送,或者采取其他替代策略。

  2. 消息类型不匹配: 当接收消息时,如果指定的消息类型在队列中不存在,msgrcv函数会返回-1,并且errno被设置为EINVAL。可以选择调整接收消息的类型,或者进行相应的错误处理。

代码示例

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

#define MSG_SIZE 128
#define SEM_KEY 1234
#define MSG_KEY 5678

// 消息结构
typedef struct msgbuf {
    long mtype;
    char mtext[MSG_SIZE];
} msgbuf;

// 信号量操作函数
void semaphore_p(int semid) {
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = -1;
    sem_op.sem_flg = SEM_UNDO;
    semop(semid, &sem_op, 1);
}

void semaphore_v(int semid) {
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = 1;
    sem_op.sem_flg = SEM_UNDO;
    semop(semid, &sem_op, 1);
}

int main() {
    int msgid, semid;
    msgbuf msg;

    // 创建消息队列
    msgid = msgget(MSG_KEY, IPC_CREAT | 0666);
    if (msgid == -1) {
        perror("msgget");
        exit(1);
    }

    // 创建信号量
    semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("semget");
        msgctl(msgid, IPC_RMID, NULL);
        exit(1);
    }

    // 初始化信号量
    if (semctl(semid, 0, SETVAL, 1) == -1) {
        perror("semctl");
        msgctl(msgid, IPC_RMID, NULL);
        semctl(semid, 0, IPC_RMID, NULL);
        exit(1);
    }

    // 发送消息
    semaphore_p(semid);
    msg.mtype = 1;
    strcpy(msg.mtext, "Hello, Message Queue!");
    if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
        if (errno == EAGAIN) {
            printf("Message queue is full. Retry later.\n");
        } else {
            perror("msgsnd");
        }
    }
    semaphore_v(semid);

    // 接收消息
    semaphore_p(semid);
    if (msgrcv(msgid, &msg, MSG_SIZE, 1, 0) == -1) {
        if (errno == EINVAL) {
            printf("Message type not found.\n");
        } else {
            perror("msgrcv");
        }
    } else {
        printf("Received message: %s\n", msg.mtext);
    }
    semaphore_v(semid);

    // 删除消息队列和信号量
    msgctl(msgid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID, NULL);

    return 0;
}

以上代码展示了如何使用信号量来同步对消息队列的访问,并处理发送和接收消息过程中的错误。