使用mqueue.h实现线程间通信时指针接收值异常问题排查
问题原因分析与修复方案
核心问题1:接收缓冲区未初始化
你的new_thread函数里,char* pArg是未初始化的野指针,调用mq_receive时,函数会尝试把接收到的指针值写入这个野指针指向的内存区域——这属于未定义行为,会导致读取到错误的地址(比如输出里的0x7f5a92279700),甚至直接触发程序崩溃。
mq_receive要求第二个参数必须是一个已分配好、大小不小于消息队列属性中mq_msgsize的缓冲区,用来存储接收到的消息内容。
核心问题2:指针解引用错误
你发送的是&data(thread_data*类型的指针),但接收时直接把pArg强转为thread_data*,相当于把缓冲区里存的指针值当成了结构体地址,正确的做法应该是先读取缓冲区里的指针值,再解引用得到结构体。
次要问题:线程创建顺序逻辑反序
主线程先发送消息再创建接收线程,虽然消息队列可以缓存消息,但从逻辑上应该先启动接收线程等待消息,再执行发送操作,避免极端情况下消息发送后线程还未完成初始化。
修复后的代码
#include <stdio.h> #include <errno.h> #include <mqueue.h> #include <pthread.h> #include <fcntl.h> #include <stdlib.h> typedef struct { mqd_t id; char* name; } thread_data; struct mq_attr attr = {0, 10, sizeof(char*), 0}; void *new_thread(void *arg) { // 分配足够存储指针的缓冲区 char* pArg = malloc(sizeof(char*)); thread_data *pData; int res; mqd_t mq_id = *(mqd_t*)arg; printf("Waiting to receive message (queue %d)...\n", mq_id); fflush(stdout); res = mq_receive(mq_id, pArg, sizeof(char*), NULL); if (res != -1) { // 读取缓冲区里的指针值,得到结构体地址 pData = *(thread_data**)pArg; printf("Message received in %p: %s\n", pData, pData->name); } else { printf("Failed! errno = %d\n", errno); } free(pArg); return NULL; } int main(int argc, char *argv[]) { pthread_t t1; thread_data data; data.name = "/thread1"; data.id = mq_open(data.name, O_RDWR | O_CREAT, 0600, &attr); if (data.id == (mqd_t)-1) { perror("mq_open failed"); return 1; } // 先创建接收线程 pthread_create(&t1, NULL, new_thread, &data.id); printf("Sending message %p (size %ld bytes)\n", &data, sizeof(char*)); int send_res = mq_send(data.id, (char*)&data, sizeof(char*), 0); if (send_res == -1) { perror("mq_send failed"); return 1; } printf("Message sent (queue %d).\n", data.id); pthread_join(t1, NULL); // 清理消息队列资源 mq_close(data.id); mq_unlink(data.name); return 0; }
额外说明
- 虽然
mqueue.h设计初衷是进程间通信,但线程间也可以正常使用,只是线程间通信更高效的方式是pthread条件变量+互斥锁、POSIX信号量等,若受限于只能使用mqueue.h,修复后的代码可以满足需求。 - 修复后的代码补充了资源清理逻辑,避免消息队列残留占用系统资源。
内容的提问来源于stack exchange,提问作者sauro
相关产品推荐
相关产品推荐

