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

mmap共享内存后初始化结构体中结构体数组出现段错误的解决方法

共享内存映射队列段错误的解决方法

问题描述

实现自定义队列结构体CustomerQueue_t并映射为进程间共享内存对象,执行mmap后初始化结构体时触发段错误,相关代码及Valgrind检测结果如下。

自定义队列代码

struct Customer {
    pid_t pid;
    int priority;
    int order;
};

typedef struct Customer Customer_t;

struct CustomerNode {
    int next;
    int filled;
    Customer_t customer;
};

typedef struct CustomerNode CustomerNode_t;

struct CustomerQueue {
    int front;
    int rear;
    int filledNodes;
    CustomerNode_t nodes[NODE_SIZE];
};

typedef struct CustomerQueue CustomerQueue_t;

初始化队列代码

void initQueue() {
    sharedQueue->front = 0;
    sharedQueue->rear = 0;
    sharedQueue->filledNodes = 0;
    sharedQueue->nodes = {0};
    for (int i = 0; i < NODE_SIZE; ++i) {
        sharedQueue->nodes[i] = (CustomerNode_t) { .next = -1, .filled = 0, (Customer_t) {-1, -1, -1 } };
    }
}

mmap相关代码

#define SHMQUEUE "SHMQUEUE"
...
CustomerQueue_t* sharedQueue;
int sharedQueueFd;
// open queue shared memory
sharedQueueFd = shm_open(SHMQUEUE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
failChecker(sharedQueueFd, "Failed to open shared memory");
failChecker(ftruncate(sharedQueueFd, sizeof(CustomerQueue_t)), "Failed to ftruncate");

// map pizza new shared memory
sharedQueue = mmap(NULL, sizeof(CustomerQueue_t*), PROT_READ | PROT_WRITE, MAP_SHARED, sharedQueueFd, 0);
if(sharedQueue == MAP_FAILED) {
   perror("Failed mmap");
   _exit(-1);
}

Valgrind检测结果(翻译后)

==14324== 无效的写操作,大小为8
==14324==    在 0x1092CA: initQueue (main.c:76)
==14324==    在 0x109376: main (main.c:103)
==14324==  地址0x7f8f1c402008位于大小为8的映射区域内
==14324==    该区域起始地址0x7f8f1c402000,长度8字节
==14324==    来自于:/dev/shm/SHMQUEUE
==14324== 
==14324== 无效的写操作,大小为4
==14324==    在 0x1092D6: initQueue (main.c:77)
==14324==    在 0x109376: main (main.c:103)
==14324==  地址0x7f8f1c40200c位于大小为8的映射区域之外
==14324==    该区域起始地址0x7f8f1c402000,长度8字节
==14324==    来自于:/dev/shm/SHMQUEUE

错误分析与修复方案

  1. mmap长度参数错误(核心问题)
    你在mmap时传入的长度是sizeof(CustomerQueue_t*)(指针大小,通常为8字节),但实际需要映射整个CustomerQueue_t结构体的内存空间,应该使用sizeof(CustomerQueue_t)。映射空间过小导致后续访问nodes数组时越界,触发段错误。

    修正后的mmap代码:

    // map pizza new shared memory
    sharedQueue = mmap(NULL, sizeof(CustomerQueue_t), PROT_READ | PROT_WRITE, MAP_SHARED, sharedQueueFd, 0);
    
  2. 数组非法赋值
    初始化代码中的sharedQueue->nodes = {0};是非法语法,C语言中不能直接对数组进行整体赋值操作,必须删除这行代码。

    修正后的initQueue函数:

    void initQueue() {
        sharedQueue->front = 0;
        sharedQueue->rear = 0;
        sharedQueue->filledNodes = 0;
        // 移除非法的数组赋值语句
        for (int i = 0; i < NODE_SIZE; ++i) {
            // 成员逐个赋值
            sharedQueue->nodes[i].next = -1;
            sharedQueue->nodes[i].filled = 0;
            sharedQueue->nodes[i].customer.pid = -1;
            sharedQueue->nodes[i].customer.priority = -1;
            sharedQueue->nodes[i].customer.order = -1;
            
            // 或者使用正确的复合字面量赋值方式
            // sharedQueue->nodes[i] = (CustomerNode_t){
            //     .next = -1,
            //     .filled = 0,
            //     .customer = {.pid = -1, .priority = -1, .order = -1}
            // };
        }
    }
    
  3. 额外注意事项

    • 确保NODE_SIZE是已定义的常量,避免因未定义导致的结构体大小计算错误。
    • 多个进程访问共享内存时,需要添加同步机制(如信号量),防止并发读写冲突。

内容的提问来源于stack exchange,提问作者kyo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 12:40:21