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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 06:40:37