C++无原生跨进程共享内存机制,Linux下应使用shm_open创建POSIX共享内存对象并mmap映射;name须以/开头、需ftruncate设大小、prot需一致、初始化避免随机值、同步需共享互斥量。

Linux 下用 mmap + shm_open 实现进程间文件映射共享内存
直接说结论:C++ 本身不提供跨进程共享内存的原生机制,必须依赖 POSIX 系统调用;在 Linux 上最稳妥的方式是用 shm_open 创建匿名共享内存对象,再用 mmap 映射到进程地址空间——它本质是“基于文件描述符的内存映射”,但不需要真实磁盘文件,也不走普通文件系统路径。
常见错误是试图用普通 open("/tmp/shm", O_CREAT) 配合 mmap,这会导致权限、同步、清理等问题;而 shm_open 创建的是 /dev/shm/ 下的 POSIX 共享内存对象,内核保证原子性与生命周期独立于进程。
-
shm_open的name参数必须以/开头(如"/myshm"),不能含其他斜杠,否则返回-1并设errno = EINVAL - 必须显式调用
ftruncate(fd, size)设置大小,mmap才能成功;否则映射区域长度为 0,读写会触发SEGV - 两个进程需用完全相同的
name和一致的prot(如都用PROT_READ | PROT_WRITE),否则映射失败或行为未定义 - 映射后建议用
memset初始化一次,避免读到随机值(尤其首次创建时)
为什么不用普通文件 + mmap?
用 open("data.bin", O_CREAT|O_RDWR) 再 mmap 理论上可行,但实际踩坑多:
- 文件需手动
ftruncate,且多个进程同时open同一路径时,可能因O_TRUNC被覆盖清空 - 进程异常退出后,文件残留,下次启动可能读到脏数据;而
shm_unlink可确保对象在所有引用关闭后自动销毁 - 普通文件映射默认是
MAP_PRIVATE,写操作不会反映到其他进程;必须用MAP_SHARED,但此时若底层文件系统不支持(如某些 NFS),mmap会失败 -
/dev/shm是 tmpfs,纯内存,无磁盘 I/O 开销,延迟更低
C++ 封装注意事项:RAII 与跨进程同步
用 RAII 自动管理 fd 和映射地址很自然,但要注意:析构函数里调用 munmap 和 close 没问题,但 shm_unlink 不能随便调——它应由最后一个退出的进程执行,否则早删了其他进程就访问不到。
立即学习“C++免费学习笔记(深入)”;
- 推荐策略:只在明确是“创建者”且负责清理的进程里调
shm_unlink(比如主控进程),子进程只做open+mmap+munmap+close - 共享内存本身不带同步机制,读写临界区必须配
pthread_mutex_t或sem_t;注意互斥量也得放在共享内存里(用PTHREAD_PROCESS_SHARED属性初始化),不能放栈或堆上 -
mmap返回的指针是void*,C++ 中强转需用static_cast(如static_cast<mystruct>(addr)</mystruct>),避免 C 风格转换引发未定义行为 - 结构体若含指针成员,不能直接 memcpy 进共享内存——指针地址在不同进程无效;应改用偏移量或序列化
一个最小可运行示例(服务端创建,客户端连接)
服务端(创建并写入):
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
<p>int main() {
const char<em> name = "/testshm";
const size_t size = 4096;
int fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(fd, size);
void</em> addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
struct Data { int flag; char msg[32]; };
auto p = static_cast<Data*>(addr);
memset(p, 0, sizeof(Data));
p->flag = 1;
strcpy(p->msg, "hello from server");
// 不 close / munmap / shm_unlink,留给客户端或后续逻辑
}</p>客户端(只读):
int fd = shm_open("/testshm", O_RDWR, 0); // name 必须完全一致
void* addr = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
auto p = static_cast<Data*>(addr);
printf("flag=%d, msg=%s\n", p->flag, p->msg); // 输出:flag=1, msg=hello from server
munmap(addr, 4096);
close(fd);
真正麻烦的从来不是映射本身,而是结构体布局是否满足 ABI 对齐、跨进程指针如何处理、以及谁来决定何时销毁共享对象——这些细节一旦错,core dump 或静默数据错乱都是常态。


















