c++如何通过文件映射mmap在多进程间实现高性能数据共享【进阶】

雨婷大大_2962

雨婷大大_2962

2026-03-30

803人浏览

原创

mmap 多进程共享必须用 MAP_SHARED,因其确保所有进程映射同一物理页并同步回文件;MAP_PRIVATE 为写时复制,修改不共享。需 O_RDWR 打开、ftruncate 预设大小,并配合适当同步机制。

c++如何通过文件映射mmap在多进程间实现高性能数据共享【进阶】

为什么 mmap 在多进程共享中必须用 MAP_SHARED 而不是 MAP_PRIVATE

因为 MAP_PRIVATE 创建的是写时复制(COW)映射,子进程或其它进程对映射区域的修改不会反映到文件,也不会被其他进程看到——它根本不是共享的。只有 MAP_SHARED 才保证所有映射该文件的进程看到同一份物理内存页,且修改会同步回文件(进而被其它进程通过映射感知)。

常见错误现象:mmap 后写入数据,另一进程读出来全是初始值或随机垃圾;strace 看到 mmap 返回成功,但 msync 失败或被忽略。

  • 必须用 open(..., O_RDWR) 打开文件,只读打开无法映射为可写 MAP_SHARED
  • 文件需预先用 ftruncate 设置足够大小,否则写越界触发 SIGBUS
  • Linux 下若挂载文件系统为 noexec 或 nosuid 一般不影响,但 nodev 不影响,真正要防的是 mand(强制访问控制)或 SELinux 限制 memprotect 类型策略

如何避免多个进程 mmap 同一文件时的竞态和初始化撕裂

文件映射本身不提供同步机制。如果进程 A 还没写完结构体头部,进程 B 就开始读,就会读到半初始化状态——这不是 mmap 的 bug,而是你没加同步。

典型使用场景:一个 producer 进程写入数据块 + 更新 ready_flag 字段,多个 consumer 进程轮询等待就绪。

  • 不要用普通变量做标志位,必须是 std::atomic_int 或 volatile sig_atomic_t 并配合 memory_order_seq_cst(C++11+)
  • 更可靠的做法是用 pthread_mutex_t 存在共享内存里,但需用 PTHREAD_PROCESS_SHARED 初始化,且所有进程必须在 mmap 后调用 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)
  • 简单方案:用 sem_open("/myshm", O_CREAT, 0644, 0) 配合命名信号量,比手搓自旋更省 CPU

mmap 映射普通文件 vs /dev/shm 的实际性能差异在哪

映射 /dev/shm/mydata(tmpfs)通常比映射磁盘文件快,但差别不在“是否落盘”,而在于页回收行为和锁竞争。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

关键差异点:

  • tmpfs 文件不经过 block layer,缺页时直接从内存分配页,无 I/O 调度延迟
  • 普通文件 mmap 在脏页回写时可能阻塞(尤其 ext4 默认 data=ordered),而 tmpfs 回写即释放,无持久化负担
  • 但 tmpfs 受 shmmax 和 shmall 内核参数限制,超限会 mmap 失败并返回 ENOMEM
  • 注意:/dev/shm 下文件仍需 ftruncate,且生命周期独立于进程——不显式 shm_unlink,重启前一直占内存

为什么 fork 后子进程能直接用父进程的 mmap 地址,但 execve 后就失效了

因为 mmap 映射是 per-process 的虚拟地址空间条目,fork 会复制整个 vma(虚拟内存区域)结构,且标记为 MAP_SHARED 时底层物理页是共享的;而 execve 会清空当前进程全部 vma,加载新程序镜像,旧映射彻底消失。

容易踩的坑:

  • 误以为 fork 出来的子进程“继承”了映射就能长期稳定通信——其实父子进程间通信没问题,但一旦子进程 execve(比如调用 system("xxx")),映射就丢了
  • 跨 exec 的方案只能是:让子进程自己重新 open + mmap 同一文件,或改用 memfd_create(Linux 3.17+)创建匿名内存文件并 fd passing,但后者需要 Unix domain socket 配合
  • 调试时用 cat /proc/PID/maps | grep yourfile 确认映射是否还存在,比猜更可靠

最麻烦的从来不是 mmap 调用本身,而是谁负责创建文件、谁负责 truncate、谁负责清理、谁在什么时候看到哪部分已写入——这些边界不厘清,性能再高也崩在启动阶段。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

4914

18

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

2025.07.04

5071

25

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

2025.10.23

794

12

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

2023.06.21

4230

4

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

2023.06.29

3573

10

linux find
linux find

find是linux命令,它将档案系统内符合 expression 的档案列出来。可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合,只有完全相符的才会被列出来。find根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部分为 path,之后的是 expression。还有指DOS 命令 find,Excel 函数 find等。本站专题提供linux find相关教程文章,还有相关

2023.06.30

2813

5

linux修改文件名
linux修改文件名

本专题为大家提供linux修改文件名相关的文章,这些文章可以帮助用户快速轻松地完成文件名的修改工作,大家可以免费体验。

2023.07.05

6890

7

linux系统安装教程
linux系统安装教程

linux系统是一种可以免费使用,自由传播,多用户、多任务、多线程、多CPU的操作系统。本专题提供linux系统安装教程相关的文章,大家可以免费体验。

2023.07.06

6542

7

linux查看文件夹大小
linux查看文件夹大小

Linux是一种自由和开放源码的类Unix操作系统,存在着许多不同的Linux版本,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。linux怎么查看文件夹大小呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.07.20

3753

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习