msgsnd/msgrcv msg_typ不一致问题求助:操作系统实验异常
问题分析与解决方案
我帮你梳理下导致msg_typ值不匹配的几个核心问题,咱们一步步来解决:
1. 消息队列索引完全搞反了
你提到queques数组的顺序是OTS、RTS、普通消息队列,也就是:
queques[0]= OTS队列IDqueques[1]= RTS队列IDqueques[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. 未检查系统调用的返回值
msgsnd和msgrcv都是可能失败的系统调用(比如队列权限错误、消息大小超限、系统中断等),但你的代码完全没做错误检查。一旦调用失败,程序会继续执行,读取的结构体字段都是未初始化的垃圾值,这也是导致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_typ是long类型。虽然赋值时不会有大问题,但显式转换可以避免类型歧义,打印时也要注意格式符匹配:
long类型用%ldint/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




