

新闻资讯
技术学院Windows用CreateFileMapping+MapViewOfFile、Linux用shm_open+mmap实现共享内存,二者均需注意大小设置、错误处理、同步机制及跨平台兼容性,且共享内存中不可存放std::string等非平凡类型。
CreateFileMapping 和 MapViewOfFile 创建共
享内存Windows 原生共享内存依赖内存映射文件(Memory-Mapped File),即使不关联磁盘文件,也能通过 INVALID_HANDLE_VALUE 创建纯内存段。关键不是“文件”,而是“映射对象”。
常见错误是传错 dwMaximumSizeHigh/dwMaximumSizeLow —— 它们合起来是 64 位大小,但多数场景用不到高位,直接设为 0 即可;若实际大小超 4GB,才需拆分赋值。
CreateFileMapping 返回 NULL 时,务必调用 GetLastError() 判断原因:权限不足(ERROR_ACCESS_DENIED)、名字冲突(ERROR_ALREADY_EXISTS)或内存不足(ERROR_NOT_ENOUGH_MEMORY)都得区分处理hMap 有效,且 MapViewOfFile 的 dwNumberOfBytesToMap 不能超过创建时声明的大小CreateEvent 或 CreateMutex 控制读写顺序HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, TEXT("MySharedMem"));
if (hMap == NULL) {
// 处理错误
}
LPVOID pMem = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
if (pMem == NULL) {
CloseHandle(hMap);
}shm_open + mmap 创建 POSIX 共享内存Linux 推荐用 POSIX 标准接口:shm_open 创建/打开一个共享内存对象(本质是 /dev/shm/ 下的虚拟文件),再用 mmap 映射进地址空间。它比 sysv shm(shmget 系列)更现代、路径可控、权限清晰。
容易忽略的是 shm_open 的 oflag 参数:跨进程通信必须带 O_RDWR,首次创建还要加 O_CREAT;同时 mode(如 0666)决定其他用户能否打开——若不设,可能被 umask 截断导致权限不足。
shm_open 返回的 fd 必须在 mmap 后 close(),否则资源泄漏(fd 不释放,但映射仍有效)mmap 的 length 必须与 ftruncate 设置的大小一致,否则读写越界或 SEGV
shm_unlink(仅删除名字,已映射的仍可用)int fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666);
ftruncate(fd, 1024);
void* ptr = mmap(nullptr, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd); // fd 可关,ptr 仍有效Windows 和 Linux 的共享内存 API 差异大,强行抽象成统一接口容易踩坑。最现实的做法是按平台条件编译,或只封装“创建/映射/销毁”三步,把同步逻辑完全交给上层。
典型陷阱包括:
"MyMem"),Linux 的 shm_open 要求以 / 开头且不能含其它斜杠("/my_mem" 合法,"/a/b" 非法)/dev/shm 大小常为 64MB,可通过 mount -o remount,size=2G /dev/shm 调整shm_unlink 类似于 Windows 的 CloseHandle + 名字注销,但 Windows 没有等价的“仅删名不关句柄”操作std::string 或虚函数对象共享内存本质是一段裸字节区域,所有数据必须是 trivially copyable,且地址无关。一旦结构体里包含 std::string、std::vector、指针、虚表指针或非 POD 成员,就绝不能直接 memcpy 进去。
例如:struct Data { std::string name; int id; }; —— name 内部指针指向堆内存,其他进程无法访问;虚函数对象的 vptr 指向本进程的虚表,跨进程失效。
char name[64])、手动序列化、或使用 boost::interprocess 提供的容器(如 boost::interprocess::basic_string)alignas(8)),避免不同编译器填充差异导致读写错位共享内存本身不难创建,难的是让两个独立进程安全、稳定、一致地解释同一片内存里的比特。类型布局、生命周期、同步粒度,这三样漏掉任何一环,都会在某个并发时机突然崩掉。