生产者进程写入共享内存:同长字符串不同数组大小为何触发段错误?
问题原因分析与解决方案
核心问题:共享内存段未被重新创建,大小不匹配导致越界
你遇到的段错误根本原因是key为1234的共享内存段已经存在,且大小小于30字节,而shmget的IPC_CREAT标志不会覆盖已存在的共享内存:
- 当你第一次运行20字节数组的代码时,系统创建了一个20字节的共享内存段(key=1234)。
- 后续运行30字节数组的代码时,
shmget发现该key的共享内存已存在,直接返回现有内存段的ID,不会创建新的30字节内存。 - 此时你通过
shmat获取的共享内存只有20字节,但memcpy(shm_addr, str, sizeof(str))会尝试写入30字节,超出了共享内存的边界,触发段错误。 - 而再次运行20字节数组的代码时,
memcpy的20字节刚好匹配现有共享内存的大小,因此不会越界报错。
验证与解决方案
验证旧共享内存的存在
用命令行查看系统中已有的共享内存:ipcs -m你会看到key为1234的共享内存段,其大小为20字节。
修复方案
- 方案1:强制创建新的共享内存段
修改shmget调用,添加IPC_EXCL标志,这样如果该key的共享内存已存在,shmget会直接报错,避免复用旧内存:int shm_id = shmget((key_t)1234, sizeof(str), IPC_CREAT | IPC_EXCL | 0666); if (shm_id == -1) { perror("shmget failed"); exit(1); } - 方案2:删除已存在的旧共享内存
用命令行删除:
或者在代码中通过ipcrm -M 1234shmctl删除(如果需要自动清理):// 在创建前检查并删除旧内存 int existing_shmid = shmget((key_t)1234, 0, 0); if (existing_shmid != -1) { shmctl(existing_shmid, IPC_RMID, NULL); } - 额外修复:避免scanf缓冲区溢出
你的scanf("%[^\n]", str)没有限制输入长度,若输入超过数组大小会导致栈溢出,建议改为:// 对应str[30]的情况,限制最多读29个字符(留1个给终止符) scanf("%29[^\n]", str); // 对应str[20]的情况 scanf("%19[^\n]", str);
- 方案1:强制创建新的共享内存段
内容的提问来源于stack exchange,提问作者Bhavesh Pendyala
相关产品推荐
相关产品推荐

