You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

msgsnd/msgrcv msg_typ不一致问题求助:操作系统实验异常

问题分析与解决方案

我帮你梳理下导致msg_typ值不匹配的几个核心问题,咱们一步步来解决:

1. 消息队列索引完全搞反了

你提到queques数组的顺序是OTS、RTS、普通消息队列,也就是:

  • queques[0] = OTS队列ID
  • queques[1] = RTS队列ID
  • queques[2] = 普通消息队列ID

但你的代码里的队列使用逻辑完全和这个顺序相反:

  • send_sync中,你把RTS消息发到了普通消息队列(queques[2]),而非RTS队列(queques[1]);从RTS队列(queques[1])接收OTS消息,而非OTS队列(queques[0]
  • rcv_sync_f中,你从普通消息队列(queques[2])接收RTS消息,而非RTS队列(queques[1]);把OTS消息发到RTS队列(queques[1]),而非OTS队列(queques[0]

这种队列混用直接导致服务器接收的不是你预期的RTS消息,而是队列里残留的旧消息或垃圾数据,自然会出现PID值错乱的问题。

2. 未检查系统调用的返回值

msgsndmsgrcv都是可能失败的系统调用(比如队列权限错误、消息大小超限、系统中断等),但你的代码完全没做错误检查。一旦调用失败,程序会继续执行,读取的结构体字段都是未初始化的垃圾值,这也是导致PID不匹配的常见原因。

比如你应该在每次调用后添加检查:

if (msgsnd(queques[1], &mrts, sizeof(message)-sizeof(long), 0) == -1) {
    perror("msgsnd RTS failed");
    exit(EXIT_FAILURE);
}

3. 类型匹配的小细节(次要但需注意)

getpid()返回的pid_t在多数系统上是int类型,而你的msg_typlong类型。虽然赋值时不会有大问题,但显式转换可以避免类型歧义,打印时也要注意格式符匹配:

  • long类型用%ld
  • int/pid_t类型用%d

修正后的代码示例

下面是调整了队列索引并添加错误检查的代码片段:

修正后的send_sync函数

void send_sync(message* m, int* queques, char* who){
    message mots, mrts;
    pid_t pid = getpid();
    mrts.msg_typ = (long)pid; // 显式转换避免类型歧义
    printf("%s: Sending of RTS Message. PID: %ld.\n", who, mrts.msg_typ);
    
    // 发送RTS到RTS队列(queques[1])
    if (msgsnd(queques[1], &mrts, sizeof(message)-sizeof(long), 0) == -1) {
        perror("msgsnd RTS failed");
        exit(EXIT_FAILURE);
    }
    printf("%s: RTS Message sent. PID: %ld. Waiting for OTS Message.\n", who, mrts.msg_typ);
    
    // 从OTS队列(queques[0])接收对应自己PID的OTS消息
    if (msgrcv(queques[0], &mots, sizeof(message)-sizeof(long), (long)pid, 0) == -1) {
        perror("msgrcv OTS failed");
        exit(EXIT_FAILURE);
    }
    printf("%s: OTS Message received. PID: %ld. Sending Message. \n", who, mots.msg_typ);
    
    m->msg_typ = (long)pid;
    // 发送普通消息到消息队列(queques[2])
    if (msgsnd(queques[2], m, sizeof(message)-sizeof(long), 0) == -1) {
        perror("msgsnd data message failed");
        exit(EXIT_FAILURE);
    }
    printf("%s: Message sent. PID: %d.\n", who, (int)pid);
}

修正后的rcv_sync_f函数

void rcv_sync_f(message* m, int* queques, char* who){
    message mots, mrts;
    printf("%s: Receiving RTS Message. PID: NOT SET YET.\n", who);
    
    // 从RTS队列(queques[1])接收任意RTS消息
    if (msgrcv(queques[1], &mrts, sizeof(message)-sizeof(long), 0, 0) == -1) {
        perror("msgrcv RTS failed");
        exit(EXIT_FAILURE);
    }
    printf("%d\n", queques[1]);
    printf("%s: RTS Message received. PID: %ld. Sending OTS Message.\n", who, mrts.msg_typ);
    
    mots.msg_typ = mrts.msg_typ;
    // 发送OTS到OTS队列(queques[0])
    if (msgsnd(queques[0], &mots, sizeof(message)-sizeof(long), 0) == -1) {
        perror("msgsnd OTS failed");
        exit(EXIT_FAILURE);
    }
    printf("%s: OTS Message sent. PID: %ld. Receiving Message.\n", who, mots.msg_typ);
    
    // 从消息队列(queques[2])接收对应客户端PID的消息
    if (msgrcv(queques[2], m, sizeof(message)-sizeof(long), mots.msg_typ, 0) == -1) {
        perror("msgrcv data message failed");
        exit(EXIT_FAILURE);
    }
    printf("%s: Message received. PID: %ld.\n", who, m->msg_typ);
}

额外建议

  • 运行程序前,用ipcrm命令清理掉之前残留的消息队列,避免旧消息干扰测试
  • ipcs命令查看当前系统的消息队列状态,确认队列ID和程序中使用的一致

内容的提问来源于stack exchange,提问作者King Powa

火山引擎 最新活动