POSIX消息队列线程间传指针值:接收端指针值不符问题
线程间使用POSIX消息队列传递指针的问题排查与修正
你编写的代码存在多处语法和逻辑错误,导致接收端无法正确获取指针值,以下是具体问题和修正方案:
核心错误点
- 错误操作
mqd_t句柄:mqd_t是消息队列的句柄(本质是整数类型),不是结构体,不能直接通过.mq_maxmsg赋值。要设置消息队列属性,需要在mq_open时传入struct mq_attr结构体参数。 mq_send参数传递错误:mq_send的第二个参数是消息数据的内存地址,你错误地将指针值ptr_value强制转换为地址,应该传递&ptr_value(即存储指针值的变量地址)。- 指针打印错误:发送端和接收端打印的都是变量自身的地址(
&ptr_value、&recv_ptr),而非变量存储的指针值。正确的打印方式是用%p输出ptr_value/recv_ptr(需转换为void*类型)。 - 代码逻辑位置错误:
threadMaster中的while(1)循环被放在mq_open失败的分支里,导致队列打开成功后根本不会进入发送逻辑。 - 变量未定义/类型错误:
rv、ERROR、CHAR未定义;64位系统下uint32_t无法容纳指针,应使用uintptr_t(来自<stdint.h>);接收端重定义了recv_ptr变量,且结构体成员访问用了.而非->。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <mqueue.h> #include <stdint.h> #include <string.h> #include <errno.h> #include <unistd.h> typedef struct { uint8_t elem1; uint8_t elem2; uint8_t elem3; } myStruct; // 全局共享内存(线程间天然共享,无需额外处理) myStruct myelements; // 消息队列句柄 mqd_t mq; void *threadMaster(void *arg) { struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = 10; attr.mq_msgsize = sizeof(uintptr_t); // 消息大小设为指针的整数类型大小 attr.mq_curmsgs = 0; // 打开消息队列,创建并设置属性 mq = mq_open("/my_queue", O_WRONLY | O_CREAT | O_EXCL, 0666, &attr); if (mq == (mqd_t)-1) { // 如果队列已存在,尝试打开 if (errno == EEXIST) { mq = mq_open("/my_queue", O_WRONLY); } if (mq == (mqd_t)-1) { perror("mq_open"); exit(EXIT_FAILURE); } } while(1) { // 更新共享数据 myelements.elem1 = 1; myelements.elem2 = 2; myelements.elem3 = 3; // 将指针转换为可存储的整数类型 uintptr_t ptr_value = (uintptr_t)&myelements; // 发送指针值:传递ptr_value的地址 int rv = mq_send(mq, (const char *)&ptr_value, sizeof(uintptr_t), 0); if (rv == -1) { perror("mq_send"); exit(EXIT_FAILURE); } // 打印实际发送的指针值 printf("Sender: Shared memory pointer = %p\n", (void*)ptr_value); sleep(1); // 避免发送过快,方便观察 } return NULL; } void *threadSlave(void *arg) { // 打开消息队列用于读取 mq = mq_open("/my_queue", O_RDONLY); if (mq == (mqd_t)-1) { perror("mq_open"); exit(EXIT_FAILURE); } while (1) { uintptr_t recv_ptr_val; // 接收指针值:写入recv_ptr_val的地址 ssize_t bytes_read = mq_receive(mq, (char *)&recv_ptr_val, sizeof(uintptr_t), NULL); if (bytes_read == -1) { perror("mq_receive"); exit(EXIT_FAILURE); } // 打印接收的指针值 printf("Receiver: Received pointer = %p\n", (void*)recv_ptr_val); // 转换为结构体指针 myStruct *data_ptr = (myStruct *)recv_ptr_val; // 访问共享数据(用->) printf("Received Data: elem1=%d, elem2=%d, elem3=%d\n", data_ptr->elem1, data_ptr->elem2, data_ptr->elem3); sleep(1); } return NULL; } int main() { pthread_t master_tid, slave_tid; // 创建线程 if (pthread_create(&master_tid, NULL, threadMaster, NULL) != 0) { perror("pthread_create master"); exit(EXIT_FAILURE); } if (pthread_create(&slave_tid, NULL, threadSlave, NULL) != 0) { perror("pthread_create slave"); exit(EXIT_FAILURE); } // 等待线程运行 sleep(10); // 关闭并删除消息队列 mq_close(mq); mq_unlink("/my_queue"); return 0; }
额外说明
- 线程间本身共享进程地址空间,全局变量
myelements天然是共享的,用消息队列传递指针更多是演示用法;如果是进程间通信,才需要配合shm_open等真正的共享内存机制。 - 编译时需要链接实时库,命令:
gcc -o thread_mq thread_mq.c -lpthread -lrt
内容的提问来源于stack exchange,提问作者JohnDoe
相关产品推荐
相关产品推荐

