MST

星途 面试题库

面试题:C语言Linux消息队列优先级冲突处理

假设在使用C语言操作Linux消息队列时,多个消息具有相同优先级,系统如何处理这种情况?如果要手动干预这种相同优先级消息的处理顺序,你会如何在代码层面实现?
14.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 系统处理相同优先级消息的方式
    • 在Linux消息队列中,当多个消息具有相同优先级时,系统通常按照“先进先出”(FIFO)的原则处理。即先发送到消息队列的消息会先被接收。这是由Linux消息队列的底层实现机制决定的,它维护了一个队列结构,在同一优先级内,新消息被追加到队列尾部,接收时从队列头部获取消息。
  2. 手动干预相同优先级消息处理顺序的代码实现
    • 方法一:自定义消息结构并排序
      • 可以在消息结构体中添加一个额外的字段,例如时间戳或者自定义的序号。
      • 以下是一个简单示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <time.h>

#define MSG_SIZE 128

// 自定义消息结构,添加时间戳字段
typedef struct {
    long mtype;
    char mtext[MSG_SIZE];
    time_t timestamp;
} MyMsgType;

// 比较函数,用于qsort排序,按照时间戳从小到大排序
int compare(const void *a, const void *b) {
    MyMsgType *msgA = (MyMsgType *)a;
    MyMsgType *msgB = (MyMsgType *)b;
    return (int)(msgA->timestamp - msgB->timestamp);
}

int main() {
    key_t key;
    int msgid;
    MyMsgType msg;
    MyMsgType msgs[10]; // 假设最多存储10个消息
    int msg_count = 0;

    // 生成唯一键值
    key = ftok(".", 'a');
    if (key == -1) {
        perror("ftok");
        return 1;
    }

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

    // 接收消息并存储到数组
    while (1) {
        if (msgrcv(msgid, &msg, MSG_SIZE, 0, IPC_NOWAIT) != -1) {
            msg.timestamp = time(NULL);
            msgs[msg_count++] = msg;
        } else {
            break;
        }
    }

    // 对消息按照时间戳排序
    qsort(msgs, msg_count, sizeof(MyMsgType), compare);

    // 重新发送消息,按照自定义顺序
    for (int i = 0; i < msg_count; i++) {
        if (msgsnd(msgid, &msgs[i], MSG_SIZE, 0) == -1) {
            perror("msgsnd");
            return 1;
        }
    }

    // 接收消息,此时消息顺序已被干预
    for (int i = 0; i < msg_count; i++) {
        if (msgrcv(msgid, &msg, MSG_SIZE, 0, 0) == -1) {
            perror("msgrcv");
            return 1;
        }
        printf("Received message: %s\n", msg.mtext);
    }

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        return 1;
    }

    return 0;
}
  • 方法二:在发送消息时添加自定义序号
    • 在消息结构体中添加一个序号字段。发送消息时,为每个消息分配一个递增的序号。接收消息后,根据序号对消息进行排序,然后再按照期望的顺序处理。这种方式与上述时间戳类似,只是使用序号来标记消息顺序。
  • 方法三:使用多个消息队列
    • 可以创建多个消息队列,例如按照某种规则(如消息的部分内容或者其他条件)将相同优先级的消息发送到不同的队列。接收时,按照期望的顺序从不同队列中获取消息。这样可以通过队列的选择来手动干预消息处理顺序。例如:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

#define MSG_SIZE 128

// 自定义消息结构
typedef struct {
    long mtype;
    char mtext[MSG_SIZE];
} MyMsgType;

int main() {
    key_t key1, key2;
    int msgid1, msgid2;
    MyMsgType msg;

    // 生成两个不同的键值
    key1 = ftok(".", 'a');
    key2 = ftok(".", 'b');
    if (key1 == -1 || key2 == -1) {
        perror("ftok");
        return 1;
    }

    // 创建两个消息队列
    msgid1 = msgget(key1, IPC_CREAT | 0666);
    msgid2 = msgget(key2, IPC_CREAT | 0666);
    if (msgid1 == -1 || msgid2 == -1) {
        perror("msgget");
        return 1;
    }

    // 发送消息到不同队列,假设根据消息内容首字母判断
    char message1[] = "Apple";
    char message2[] = "Banana";
    msg.mtype = 1;
    if (message1[0] < message2[0]) {
        strcpy(msg.mtext, message1);
        if (msgsnd(msgid1, &msg, MSG_SIZE, 0) == -1) {
            perror("msgsnd");
            return 1;
        }
        strcpy(msg.mtext, message2);
        if (msgsnd(msgid2, &msg, MSG_SIZE, 0) == -1) {
            perror("msgsnd");
            return 1;
        }
    } else {
        strcpy(msg.mtext, message2);
        if (msgsnd(msgid1, &msg, MSG_SIZE, 0) == -1) {
            perror("msgsnd");
            return 1;
        }
        strcpy(msg.mtext, message1);
        if (msgsnd(msgid2, &msg, MSG_SIZE, 0) == -1) {
            perror("msgsnd");
            return 1;
        }
    }

    // 按照期望顺序接收消息
    if (msgrcv(msgid1, &msg, MSG_SIZE, 1, 0) == -1) {
        perror("msgrcv");
        return 1;
    }
    printf("Received from msgid1: %s\n", msg.mtext);
    if (msgrcv(msgid2, &msg, MSG_SIZE, 1, 0) == -1) {
        perror("msgrcv");
        return 1;
    }
    printf("Received from msgid2: %s\n", msg.mtext);

    // 删除消息队列
    if (msgctl(msgid1, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        return 1;
    }
    if (msgctl(msgid2, IPC_RMID, NULL) == -1) {
        perror("msgctl");
        return 1;
    }

    return 0;
}

通过以上方法,可以手动干预相同优先级消息在Linux消息队列中的处理顺序。