syscall.Mmap单独无法实现跨进程同步,因其映射普通文件时各进程物理页不一致;必须组合shm_open+mmap+POSIX信号量等跨进程同步原语,确保共享内存对象和同步机制均具内核级可见性。
不能用直接实现跨进程数据同步——它映射的是普通文件,内核不保证多进程间物理页一致;必须组合++ 跨进程同步原语,否则写入对另一进程不可见。
为什么
单独调用无法同步
常见错误现象:
返回成功,进程 A 写了数据,进程 B 读到空值、旧值或乱码。
根本原因:普通文件(如
打开的)被两个进程各自
后,Linux 不强制它们映射到同一块物理内存页。即使都用
,写操作只刷新本进程的页缓存,不触发跨进程可见性。
关键区别:
创建的是 POSIX 共享内存对象(内核级),所有打开它的进程共享同一 backing store
打开的是普通文件,
后仍是独立的文件映射实例
本身不识别“共享内存语义”,它只忠实地按 fd 类型执行映射
必须用
+
的完整流程
这是 Linux/macOS 上唯一可落地的路径。Windows 完全不支持
,需换方案(如命名管道或内存映射文件 via CreateFileMapping)。
进程 A(创建者):
调用
立刻
—— 必须在
前,否则
返回
再
进程 B(加入者):
调用
—— 不带
,否则可能覆盖
建议也
并校验大小,避免长度不一致导致越界访问
同样
,参数与 A 完全一致
示例关键片段(省略错误检查):
同步机制不能靠
或
常见误用:
字段含指针和 runtime 状态,放到 mmap 区域里会 panic;
只在单进程地址空间内原子,跨进程完全无效。
正确做法:同步原语本身也得驻留在共享内存中,并由 OS 保证跨进程语义:
POSIX 信号量:
,然后
/
自旋锁 +
需手动实现,且必须用
操作共享内存中的 uint32 字段(该字段需对齐、初始化为 0)
注意:sem_open 名称在 macOS 必须以
开头、不能含多余斜杠;Linux 更宽松但需链接
容易被忽略的生命周期与清理细节
最常漏掉的三件事:
必须由最后一个使用者调用,且通常应在所有进程都
后 —— 提前 unlink 不影响已映射进程,但新进程无法再打开
是必须的,不调用会导致资源泄漏(尤其长期运行服务)
进程异常退出时,共享内存对象不会自动销毁,需靠
显式清理,否则下次启动可能因残留对象而失败
实际部署中,建议用临时名称(如带 PID 或 UUID 后缀)+ 启动时尝试
清理旧对象,避免残留。
syscall.Mmapshm_openmmapsyscall.Mmapsyscall.Mmapos.OpenmmapMAP_SHAREDshm_openos.Openmmapsyscall.Mmapshm_openmmapshm_opensyscall.ShmOpen("/myshm", syscall.O_CREAT|syscall.O_RDWR, 0600)syscall.Ftruncate(fd, size)mmapmmapEINVALsyscall.Mmap(fd, 0, size, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)syscall.ShmOpen("/myshm", syscall.O_RDWR, 0)O_CREATFtruncateMmapfd, _ := syscall.ShmOpen("/go_shm", syscall.O_CREAT|syscall.O_RDWR, 0600)
syscall.Ftruncate(fd, 4096)
data, _ := syscall.Mmap(fd, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)sync.Mutexatomicsync.Mutexatomic.CompareAndSwapUint32sem_open("/mysem", syscall.O_CREAT, 0600, 1)sem_waitsem_postatomicatomic.CompareAndSwapUint32/-lrtshm_unlinkmunmapsyscall.Munmapshm_unlinkshm_unlink