在 Windows 操作系统中,共享内存是用于在多个进程之间共享数据的一种机制。你可以使用 Windows API 创建共享内存区域,从而在不同的进程之间传递数据。以下是实现共享内存的主要步骤:
1. 创建或打开一个文件映射对象
共享内存的核心是在内存中创建一个文件映射对象。使用 CreateFileMapping
API 来创建或打开这个对象。
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用页面文件,而不是物理文件
NULL, // 默认安全属性
PAGE_READWRITE, // 读写访问
0, // 高位文件大小(0表示不指定大小)
bufferSize, // 低位文件大小,表示共享内存的大小
L"Global\\MySharedMemory"); // 共享内存的名称
参数说明:
INVALID_HANDLE_VALUE
表示不使用实际文件,而是基于内存分页文件。PAGE_READWRITE
表示该内存区域可读可写。bufferSize
是共享内存的大小,单位为字节。L"Global\\MySharedMemory"
是共享内存对象的名称,不同进程可以通过该名称访问同一共享内存。
2. 映射共享内存到当前进程的地址空间
通过 MapViewOfFile
函数,将文件映射对象映射到当前进程的地址空间,返回指向共享内存区域的指针。
LPVOID pBuf = MapViewOfFile(
hMapFile, // 共享内存对象的句柄
FILE_MAP_ALL_ACCESS, // 读写权限
0, // 高位文件偏移
0, // 低位文件偏移
bufferSize); // 映射的字节数
pBuf
是指向共享内存区域的指针,后续你可以使用它来读写共享内存中的数据。
3. 读写共享内存
你可以通过指向共享内存区域的指针 pBuf
来读写数据,例如:
// 写入数据
CopyMemory((PVOID)pBuf, someData, dataSize);
// 读取数据
CopyMemory(destinationBuffer, (PVOID)pBuf, dataSize);
4. 解除内存映射并关闭句柄
在使用完共享内存后,应该解除映射并关闭文件映射对象句柄。
UnmapViewOfFile(pBuf); // 解除映射
CloseHandle(hMapFile); // 关闭句柄
5. 访问共享内存的另一个进程
要访问已经创建的共享内存,另一个进程只需通过 OpenFileMapping
打开现有的文件映射对象:
HANDLE hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // 读写权限
FALSE, // 子进程继承句柄标志
L"Global\\MySharedMemory"); // 同样的共享内存名称
打开后,和第一进程一样,通过 MapViewOfFile
将其映射到进程地址空间并进行数据操作。
实例
下面是一个使用共享内存的完整 C 语言实例,展示了两个进程之间如何通过共享内存传递数据。第一个进程创建共享内存并写入数据,第二个进程读取共享内存中的数据。
进程1:创建共享内存并写入数据
#include <windows.h>
#include <stdio.h>
int main() {
// 共享内存大小
const int bufferSize = 256;
// 创建文件映射对象(共享内存)
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用页面文件
NULL, // 默认安全属性
PAGE_READWRITE, // 读写访问
0, // 高位文件大小
bufferSize, // 共享内存大小
L"Global\\MySharedMemory"); // 共享内存的名称
if (hMapFile == NULL) {
printf("Could not create file mapping object (%d).\n", GetLastError());
return 1;
}
// 将共享内存映射到进程地址空间
LPCTSTR pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, bufferSize);
if (pBuf == NULL) {
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
// 写入数据到共享内存
const char* message = "Hello from Process 1!";
memcpy((PVOID)pBuf, message, (strlen(message) + 1) * sizeof(char));
printf("Process 1: Written message to shared memory: %s\n", message);
// 等待用户输入,保持进程不退出
getchar();
// 解除映射并关闭句柄
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
进程2:读取共享内存中的数据
c复制代码#include <windows.h>
#include <stdio.h>
int main() {
// 共享内存大小
const int bufferSize = 256;
// 打开已存在的文件映射对象(共享内存)
HANDLE hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // 读写权限
FALSE, // 子进程不能继承句柄
L"Global\\MySharedMemory"); // 共享内存的名称
if (hMapFile == NULL) {
printf("Could not open file mapping object (%d).\n", GetLastError());
return 1;
}
// 将共享内存映射到进程地址空间
LPCTSTR pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, bufferSize);
if (pBuf == NULL) {
printf("Could not map view of file (%d).\n", GetLastError());
CloseHandle(hMapFile);
return 1;
}
// 从共享内存中读取数据
printf("Process 2: Read message from shared memory: %s\n", pBuf);
// 解除映射并关闭句柄
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0;
}
运行步骤:
- 先运行 进程1,它会创建共享内存并写入一条消息(
Hello from Process 1!
)。 - 运行 进程2,它会打开共享内存并读取进程1写入的消息。
- 你可以在进程1结束前(通过
getchar()
暂停)运行进程2,查看它读取到的共享内存内容。
关键点:
CreateFileMapping
用于创建共享内存。MapViewOfFile
用于将共享内存映射到当前进程的地址空间。OpenFileMapping
用于打开已存在的共享内存(在另一个进程中创建)。- 共享内存是通过名称
Global\\MySharedMemory
在多个进程之间共享的。
这两个程序可以展示如何通过共享内存在不同的进程之间传递数据。