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
错误分析与修复方案
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);数组非法赋值
初始化代码中的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} // }; } }额外注意事项
- 确保
NODE_SIZE是已定义的常量,避免因未定义导致的结构体大小计算错误。 - 多个进程访问共享内存时,需要添加同步机制(如信号量),防止并发读写冲突。
- 确保
内容的提问来源于stack exchange,提问作者kyo
相关产品推荐
相关产品推荐

