shm_open + mmap 是 Linux 下最可控、最轻量的共享内存方案,因其生命周期独立、大小可调、映射安全且避免 ftok 不确定性;需配合 __attribute__((packed))、固定宽度类型、命名信号量及严格 ftruncate/mmap 顺序。

直接用 shm_open + mmap 是 Linux 下最可控、最轻量的方案,别碰 shmget/shmat(System V),除非你在维护 20 年前的遗留代码。
为什么 shm_open + mmap 比 shmget 更可靠
POSIX 共享内存对象(shm_open 创建)是内核级命名对象,生命周期独立于进程,名字以 / 开头(如 "/my_shm"),不占文件系统路径,也不会被误删。而 shmget 依赖 ftok 生成 key,一旦文件路径或 proj_id 变动,key 就失效,两个进程根本连不到同一块内存——线上查了三天发现是 ftok("a.txt", 65) 和 ftok("b.txt", 65) 算出不同 key,这种坑纯属白费时间。
关键差异点:
-
shm_open返回 fd,能直接用ftruncate控制大小,映射前必须调;shmget的 size 是创建时定死的,扩容得重建 -
mmap映射后指针可直接当数组用;shmat返回的 void* 得强转,且分离后指针变悬空,容易误用 -
shm_unlink可安全清理,只要所有进程都已munmap,对象就自动销毁;shmctl(..., IPC_RMID)是立即删,哪怕还有进程 attach 着,下次访问直接 SIGBUS
结构体布局错位:__attribute__((packed)) 不是可选项
共享内存里放结构体?不加 __attribute__((packed)) 几乎必错。编译器默认按 8 字节对齐,x86_64 上 struct { uint8_t a; uint64_t b; } 在一个进程里占 16 字节,在另一个进程(比如开了 -O2 或换了 Clang)可能只占 9 字节——读写偏移一错,数据全乱。
必须做到:
- 所有字段用固定宽度类型:
uint32_t、int64_t,不用int或long - 禁用
std::string、std::vector:它们内部指针指向各自进程堆,另一方解引用就是段错误 - 数组用定长:
char data[1024],别用char*动态分配 - 示例正确写法:
struct __attribute__((packed)) ShmPacket { uint32_t seq; uint16_t len; char payload[512]; };
同步机制选型:信号量比互斥量更稳妥
别把 pthread_mutex_t 放共享内存里用 PTHREAD_PROCESS_SHARED——它要求初始化只能由第一个进程做,且必须在映射后的内存地址上 pthread_mutex_init;如果第二个进程启动稍快,抢在初始化前就去 lock,行为未定义,大概率卡死。
推荐用 sem_open 创建命名信号量,原因很实在:
- 信号量是内核对象,生命周期由内核管理,进程崩溃也不会残留锁状态
- 支持
sem_wait/sem_post原语,天然适配生产者-消费者模型(比如环形缓冲区的空/满信号量) - 名字也以
/开头(如"/my_shm_sem"),和共享内存对象统一管理 - 注意权限:
sem_open(name, O_CREAT, 0644, 1)中的0644必须设,否则其他用户进程打不开
常见 SIGBUS 错误:ftruncate 和 mmap 顺序不能反
这是新手最高频的崩溃点:调了 mmap 后才 ftruncate,或者压根忘了 ftruncate。结果 mmap 映射的是 0 长度区域,一写就触发 SIGBUS(不是 SEGFAULT)。
正确顺序铁律:
fd = shm_open(name, O_CREAT | O_RDWR, 0600)-
ftruncate(fd, size)—— 必须在这一步设好大小 ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)-
close(fd)—— 映射后 fd 可关,不影响 ptr 使用
另外,size 最好是页对齐(sysconf(_SC_PAGESIZE) 的整数倍),否则某些内核版本下 mmap 可能静默截断,导致越界写不报错但数据丢失。
真正难的从来不是映射那几行代码,而是结构体字节对齐是否一致、信号量是否被意外残留、以及某个进程异常退出后有没有人负责 shm_unlink。这些地方一松懈,问题就变成“偶尔错、重启就好、无法复现”——比 crash 还难搞。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











