C语言共享内存中SharedMem结构体内置信号量初始化报错咨询
报错原因定位
你当前的调用存在两处参数错误,直接导致初始化失败:
- 第一处地址取指错误:
sem_init(&shm, 0, 1)中,shm本身是指向SharedMem结构体的指针,&shm取的是这个指针变量本身的栈内存地址,并非结构体内部sem成员的地址,类型与sem_init要求的*sem_t**参数完全不匹配,会直接触发参数校验报错。 - 第二处共享模式参数错误:
sem_init的第二个参数pshared传0时,代表该信号量为同进程内的线程共享使用,此时信号量的存储位置必须是进程私有地址空间;如果要实现多进程通过共享内存访问同一个信号量,该参数必须传非0值,明确告知内核该信号量为跨进程共享模式。
修正后的实现方案
核心调整逻辑:
- 仅由首次创建共享内存段的进程执行信号量初始化,避免多进程挂载时重复初始化覆盖信号量的计数值,破坏互斥逻辑。
- 严格按照参数要求传入对应值:第一个参数传入共享内存内
sem成员的地址,第二个参数传1标记跨进程共享,第三个参数传入需要的信号量初始值。
修正后的核心代码示例:
#include <errno.h> // 标记当前进程是否是共享内存段的首次创建者 int is_new_segment = 0; // 先以排他模式尝试新建共享内存 int shmid = shmget(sharedMemKey, sizeof(SharedMem), IPC_CREAT | IPC_EXCL | 0666); if (shmid < 0) { // 排他创建失败说明共享内存段已存在,直接获取已有段 if (errno == EEXIST) { shmid = shmget(sharedMemKey, sizeof(SharedMem), 0666); if (shmid < 0) { printf("共享内存获取失败\n"); return 1; } } else { printf("共享内存创建失败\n"); return 1; } } else { is_new_segment = 1; } // 挂载共享内存到当前进程地址空间 SharedMem *shm = shmat(shmid, NULL, 0); if (shm == (SharedMem *)-1) { printf("共享内存挂载失败\n"); return 1; } shm->shmid = shmid; // 仅首次创建段的进程负责初始化信号量 if (is_new_segment) { // 正确的sem_init调用:传入结构体内部sem成员地址,标记跨进程共享,初始值1 if (sem_init(&shm->sem, 1, 1) < 0) { printf("信号量初始化失败,错误码:%d\n", errno); // 初始化失败时清理已创建的共享内存,避免资源泄漏 shmctl(shmid, IPC_RMID, NULL); return 1; } }
注意事项
- 跨进程共享信号量依赖内核的POSIX信号量支持,需要确保运行环境支持
pshared非0的共享模式。 - 共享内存段生命周期结束时,需要先调用
sem_destroy(&shm->sem)释放信号量资源,再调用shmctl(shmid, IPC_RMID, NULL)删除共享内存段。 - 禁止多个进程挂载共享内存后重复执行
sem_init,否则会覆盖信号量的当前运行计数值,导致互斥逻辑失效。
内容的提问来源于stack exchange,提问作者mikk prize
相关产品推荐
相关产品推荐

