共享内存写入前必须先调用mmap映射,否则直接写入会触发Segmentation fault;需严格按shm_open→ftruncate→mmap→写入顺序操作,且mmap必须使用MAP_SHARED和PROT_WRITE标志。

共享内存写入前必须先映射 shm_open + mmap
直接对未映射的共享内存段地址写入会触发 Segmentation fault。C++ 没有“共享内存对象”的抽象封装,所有操作都依赖 POSIX 系统调用,必须严格按顺序:创建/打开 → 设置大小 → 映射 → 写入。
常见错误是跳过 ftruncate 设置大小,导致 mmap 返回 MAP_FAILED;或映射时漏掉 PROT_WRITE 标志,后续写入触发 SIGBUS。
-
shm_open("/my_shm", O_CREAT | O_RDWR, 0666)返回文件描述符,路径名必须以/开头(POSIX 要求) - 立刻调用
ftruncate(fd, size),否则mmap可能成功但实际不可写 -
mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)中MAP_SHARED不可替换为MAP_PRIVATE,否则写入不透出到其他进程
写入时注意结构体对齐与跨进程一致性
如果往共享内存写入自定义结构体(比如 struct Packet { int id; double ts; char data[256]; }),不同进程编译时结构体布局可能不一致——尤其是启用 -m32/-m64、不同编译器、或加了 #pragma pack 时。
典型现象:进程 A 写入后,进程 B 读出 id 是乱码,ts 值偏移 2 字节。这不是共享内存问题,而是内存布局错位。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 强制使用
static_assert(std::is_standard_layout_v<packet>)</packet>编译期检查 - 显式指定对齐:
struct alignas(8) Packet { ... };,并确保所有进程用相同alignas值 - 避免虚函数、继承、非 POD 成员;优先用
uint8_t替代char,明确字节语义 - 写入前用
memset(ptr, 0, sizeof(Packet))清零,防止 padding 区域残留脏数据影响调试
写入后需同步:msync 并非总是必要,但边界场景必须用
msync(ptr, size, MS_SYNC) 强制将修改刷入底层共享内存对象,通常用于确保另一进程能立即看到变更。但多数情况下,只要用了 MAP_SHARED,内核会在页换出或进程退出时自动同步——所以日常轮询读取一般不用 msync。
必须用的场景:写入后立刻调用 exit() 或 _exit(),且没做 munmap;或者写入关键标志位(如 ready = 1)后希望另一进程无延迟感知。
- 只对已
mmap的地址调用msync,传错地址会返回-1并置errno = EINVAL - 不要在循环内频繁
msync,它会引发内核页表刷新,性能开销大(实测比纯写入慢 10x+) - 更轻量的替代:用
std::atomic_thread_fence(std::memory_order_release)配合 flag 变量,比msync更快且可移植
销毁共享内存前务必 munmap + shm_unlink
仅关闭 fd 不会释放共享内存,也不删除名字。若进程异常退出未清理,该段内存会一直驻留 /dev/shm 目录下,直到系统重启或手动 rm /dev/shm/my_shm。
典型问题:开发时反复运行程序,shm_open 总返回已有段,但内容是上次残留,误以为写入失败。
- 每个
mmap对应一次munmap(ptr, size),即使映射失败也要检查ptr != MAP_FAILED -
shm_unlink("/my_shm")应放在所有进程都完成映射和使用之后——通常是服务端主进程退出前,或由约定的“管理者进程”执行 - 若需支持热重载,可改用引用计数机制(例如在共享内存头部存一个
int refcount),而不是依赖shm_unlink时机
/dev/shm 下还躺着一个 1GB 的残留文件。


















