You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 13:55:53