shm_open + mmap 是 Linux 下最直接、最可控的 C++ 共享内存方案,但必须严格按顺序操作:先 shm_open 创建对象,再 ftruncate 设置大小,最后 mmap 映射;需注意命名规范、权限设置、结构体对齐、POD 类型限制及跨进程同步机制。

shm_open + mmap 是 Linux 下最直接、最可控的 C++ 共享内存方案,但必须严格按顺序操作,否则一写就段错误或读出乱码。
shm_open 之后必须立刻 ftruncate
很多人调完 shm_open 就急着 mmap,结果 mmap 成功返回了非空指针,一写就 SIGBUS。这是因为:
- shm_open 只创建一个“空壳”对象,初始大小为 0
- mmap 能映射成功,不代表你能访问任意偏移——越界访问触发总线错误
- 必须在 mmap 前调 ftruncate(fd, size) 显式设定字节长度
-
shm_open("/my_shm", O_CREAT | O_RDWR, 0666)中名字必须以/开头,不能含空格或点(如/my.shm会失败) - 权限掩码别用
0600,否则其他进程打不开;0666是安全起点 - 调
ftruncate后要检查返回值,失败时errno可能是EINVAL(fd 不合法)或EBADF
mmap 参数错一个标志就白忙活
mmap 的 prot 和 flags 组合不对,会导致写入不生效、只读、或跨进程不可见:
- 写入必须带
PROT_WRITE,只读进程至少得有PROT_READ -
flags必须是MAP_SHARED;用MAP_PRIVATE写入只改本地副本,另一方永远看不到 - 返回值必须检查是否等于
MAP_FAILED;直接当有效地址用会段错误 - 映射地址建议传
nullptr让内核选,别硬指定0x10000000这类固定值(易冲突)
结构体写进共享内存前必须控制布局
两个进程分别编译,哪怕代码完全一样,sizeof(Header) 也可能不同——这是对齐惹的祸。现象是:A 进程写入 id=123,B 进程读出来是 0 或随机值。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 禁用默认对齐:
struct __attribute__((packed)) Header { uint32_t id; char name[64]; }; - 或者用
#pragma pack(1)(MSVC 兼容),但需确保所有进程用相同方式编译 - 避免
std::string、std::vector;它们内部指针指向各自进程堆,另一方解引用即崩溃 - 推荐只放 POD 类型:
int32_t、char[256]、uint64_t;必要时用union做类型双关(注意严格别名规则)
没同步机制的共享内存就是定时炸弹
共享内存本身不提供任何原子性或互斥能力。两个进程同时改同一字段,结果大概率是丢失更新或结构体半写半读。
立即学习“C++免费学习笔记(深入)”;
-
std::mutex不能放共享内存里——它是进程内对象,跨进程无效 - 正确做法:用
sem_open("/my_sem", O_CREAT, 0666, 1)创建命名信号量,配sem_wait/sem_post - 或者把
pthread_mutex_t放在共享内存里,用pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)初始化(仅限第一个进程初始化一次) - 别依赖
msync做同步——它刷页表,不是锁;真正需要的是互斥原语 + 内存屏障(如std::atomic_thread_fence)
真正容易被忽略的是:shm_unlink 不是立即删除,而只是标记待删;所有进程都 munmap 后,内核才真正回收。如果某个进程崩溃没清理,/dev/shm/my_shm 会残留,下次 shm_open 会打开旧对象——数据还是上次的,但结构体版本可能已变。

















