Ubuntu20下IPC信号量程序新增未用信号量后异常崩溃调试求助
问题根本原因
- master与slave的共享内存结构体定义不一致:当你开启
#define BUG 1时,master.c中的sharedmem_t结构体多了sem_t sem_top字段,但slave.c中的同名字段没有同步更新这个成员。直接引发两类问题:- 共享内存大小不匹配:master调用
shmget时申请的是包含sem_top的更大内存空间,而slave调用shmget传入的是自身更小的结构体尺寸,如果系统有残留的共享内存段,会直接匹配到旧段,不会按新结构体重分配。 - 成员内存偏移错位:master侧的
cmd字段位于sem_top之后,而slave侧的cmd紧跟在sem_done数组之后,两边读写信号量、读写cmd的地址完全偏移,哪怕你没有实际使用sem_top,也会出现随机挂起、进程异常退出的问题。
- 共享内存大小不匹配:master调用
- 残留IPC资源干扰:System V标准的IPC资源(共享内存、信号量)是内核持久化的,只要不主动删除或者系统重启,就算进程退出也会一直留存。如果之前测试时程序异常退出,没有执行到最后
shmctl(IPC_RMID)的清理逻辑,key=12345的共享内存段会一直留在系统中,后续运行程序时会直接复用旧段,进一步加剧内存错位问题。
修复方案
- 统一共享内存结构体定义:把
sharedmem_t的定义抽取到单独的公共头文件中,master.c和slave.c都引用这个头文件,避免两边结构定义不同步,开启BUG宏时slave侧的结构体也要同步包含sem_top字段。 - 启动前清理残留IPC资源:每次运行程序前可以先执行
ipcs -m查看共享内存段,用ipcrm -M 12345命令按key删除残留段,也可以在代码中启动时先清理旧段再创建新段:
// 先尝试删除旧的共享内存段 shmid = shmget(key, sizeof(sharedmem_t), 0666); if (shmid >= 0) { shmctl(shmid, IPC_RMID, NULL); } // 再创建新的共享内存段 shmid = shmget(key, sizeof(sharedmem_t), 0666|IPC_CREAT);
- 补充错误日志输出:把现有的错误打印替换为
perror,可以直接输出系统错误码对应的原因,快速定位调用失败的根因。
这类IPC问题的通用调试方法
- 优先排查残留IPC资源:每次复现问题前先清理系统中残留的共享内存、信号量队列,排除历史数据干扰。
- 校验成员地址偏移:可以在master和slave中分别打印
&shmp->sem_start[0]、&shmp->cmd等关键成员的地址,对比两边的偏移是否一致,能快速定位结构体定义不一致的问题。 - 用strace追踪系统调用:执行
strace -p <进程ID>可以查看挂起进程到底阻塞在哪个系统调用上、传入的参数是什么,快速定位是哪个信号量操作出了问题。
内容的提问来源于stack exchange,提问作者R71
相关产品推荐
相关产品推荐

