共享内存概念介绍
在Windows平台上,共享内存是一种进程间通信(IPC)机制,允许两个或多个进程共享一个公共内存区域,以便它们可以读取、写入或修改位于该内存区域中的数据。
共享内存提供了一种快速且高效的数据交换方式,因为它允许进程直接访问同一块物理内存,而无需数据复制。
在Windows平台上,使用C++进行共享内存的通信可以通过WinAPI中的CreateFileMapping
和MapViewOfFile
函数来实现。
使用UnmapViewOfFile
函数来撤销映射的视图,使用CloseHandle
函数来关闭文件映射对象的句柄。
-
文件映射对象(File Mapping)
- 在Windows中,共享内存通常是通过文件映射对象实现的。一个文件映射对象可以基于一个实际的文件,或者是一个匿名的内存区域。
- 使用
CreateFileMapping
函数创建文件映射对象,并指定其大小和名称。
-
内存映射文件(Memory-Mapped File)
- 将文件内容或内存区域映射到进程的地址空间,使得文件内容或内存区域就像进程的普通内存一样可以被访问。
- 使用
MapViewOfFile
函数将文件映射对象的视图映射到调用进程的地址空间。
-
视图(View)
- 每个映射文件视图代表文件映射对象的一个特定部分,可以独立控制对这部分的访问权限和偏移量。
- 一个文件映射对象可以有多个视图,每个视图可以被不同的进程或同一进程的不同线程所使用。
-
同步机制(Synchronization)
- 由于多个进程可以同时访问共享内存,因此需要同步机制来避免竞态条件和数据不一致问题。
- 可以使用互斥锁(Mutexes)、信号量(Semaphores)或临界区(Critical Sections)等同步机制来保护共享资源。
-
命名与匿名共享内存
- 命名共享内存具有名称,可以通过文件系统进行访问,适用于不同进程间的通信。
- 匿名共享内存没有名称,通常用于具有亲缘关系的进程间通信,如父子进程。
-
访问权限(Access Rights)
- 创建文件映射对象时,可以指定不同的访问权限,如
PAGE_READONLY
、PAGE_READWRITE
等,以控制进程对共享内存的读写能力。
- 创建文件映射对象时,可以指定不同的访问权限,如
-
内存管理
- 操作系统负责管理共享内存的生命周期,包括内存分配、保护和释放。
- 使用
UnmapViewOfFile
函数来撤销映射的视图,使用CloseHandle
函数来关闭文件映射对象的句柄。
-
性能考虑
- 共享内存通常提供比基于消息或套接字的IPC机制更快的数据传输速度,因为它减少了数据复制的开销。
-
安全性
- 需要考虑共享内存的安全性,确保只有授权的进程可以访问共享内存区域,防止潜在的安全隐患。
共享内存是一种强大的IPC机制,但它也需要谨慎使用,以确保数据的一致性和进程间的同步。在设计使用共享内存的应用程序时,开发者应该仔细考虑同步机制、错误处理和资源管理。
进程1创建内存映射:CreateFileMapping
#include <windows.h>
#include <iostream>
#include <string>
// 共享内存中的数据结构
struct SharedData {
LONG counter; // 计数器
};
int main() {
// 创建或打开一个文件映射对象
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用系统分页文件
NULL, // 默认安全性
PAGE_READWRITE, // 读写权限
0, // 最大对象大小(字节)
sizeof(SharedData), // 分配的初始大小
L"MySharedMemory"); // 映射对象名称
if (hMapFile == NULL)
{
return 1;
}
// 映射文件视图到进程的地址空间
SharedData* pData = static_cast<SharedData*>(MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS, // 读写权限
0,
0,
sizeof(SharedData)
));
if (pData == NULL) {
CloseHandle(hMapFile);
return 1;
}
// 初始化共享数据
pData->counter = 0;
// 模拟数据操作
for (int i = 0; i < 10; ++i) {
pData->counter += i; // 修改共享数据
std::cout << "Process 1: counter = " << pData->counter << std::endl;
Sleep(500); // 等待半秒
}
// 完成数据操作后,取消映射
if (!UnmapViewOfFile(pData)) {
std::cerr << "UnmapViewOfFile failed (Error: " << GetLastError() << ")" << std::endl;
}
// 关闭文件映射对象句柄
if (!CloseHandle(hMapFile)) {
std::cerr << "CloseHandle failed (Error: " << GetLastError() << ")" << std::endl;
}
return 0;
}
进程二打开内存映射:OpenFileMapping