posix共享内存需用shm_open(name以/开头)、ftruncate设大小、mmap配map_shared;写后不立即可见因缓存与重排,须用内存栅栏或锁同步;munmap后指针变野指针,需置nullptr并确保无访问。

共享内存本身不提供同步机制,直接用 shmget + shmat 写多进程数据,大概率读到脏数据或崩溃。
怎么安全地创建和映射 POSIX 共享内存(shm_open)
linux/macos 推荐用 POSIX API,比 SysV(shmget)更轻、路径可控、支持 fcntl 锁。windows 用 CreateFileMapping,但跨平台优先选 POSIX。
-
shm_open的name必须以/开头,比如"/my_shm",不能是"my_shm"或"./my_shm",否则返回-1并设errno = ENOENT - 记得调用
ftruncate设置大小,否则mmap会失败并报errno = EINVAL - 映射时建议加
MAP_SHARED,用MAP_PRIVATE改动不会同步到其他进程
int fd = shm_open("/log_buf", O_CREAT | O_RDWR, 0644); ftruncate(fd, 4096); void* ptr = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
为什么写完不立刻被其他进程看到?——缓存与内存序问题
CPU 和编译器都可能重排写操作,尤其在多核机器上。即使用了 MAP_SHARED,一个进程写了字段 A,另一个进程仍可能读到旧值。
- 别依赖“写完就可见”,必须显式同步:用
std::atomic_thread_fence(c++11+),或__sync_synchronize()(GCC) - 如果共享结构体里有多个字段需原子更新(比如状态+数据),不要单独用
std::atomic<int></int>包裹每个字段——它们不是事务性的;改用自旋锁或信号量保护整个临界区 - 避免用
volatile当同步手段,它不阻止指令重排,也不保证跨线程可见性
常见崩溃点:shmdt / munmap 后继续访问指针
映射解除后,指针变成野指针,但访问不一定立刻段错误——可能读到旧页缓存、也可能触发 SIGSEGV,行为不可预测。
立即学习“C++免费学习笔记(深入)”;
- 解除映射前,确保所有线程已退出对该内存的访问;可配合引用计数或进程间信号通知
- 解除后立即将指针置为
nullptr,避免后续误用 - 注意:
shm_unlink不等于立即销毁内存,只要还有进程挂载着,内容就保留;真正释放要等最后一个shmdt或munmap
共享内存最麻烦的从来不是创建或映射,而是确定哪些字节谁在读、谁在写、什么时候能读、什么时候必须等——没配好同步原语,性能再高也是错的。