c++共享内存
·
文章目录
c++共享内存
什么是共享内存
共享内存是进程间通信(IPC)的一种方式,允许多个进程访问同一块内存区域,实现数据共享,它是所有IPC方式中速度最快的,因为数据不需要在进程间拷贝。
| API | 作用 |
|---|---|
CreateFileMapping |
创建/打开一个文件映射对象(共享内存) |
OpenFileMapping |
打开一个已存在的文件映射对象 |
MapViewOfFile |
将文件映射对象映射到当前进程的地址空间 |
UnmapViewOfFile |
取消映射 |
CloseHandle |
关闭句柄 |
完整示例:
服务端
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;
#define BUF_SIZE 1024
int main() {
char szBuffer[] = "哈哈哈,C++共享内存实战";
// 1. 创建共享内存对象(-1 表示使用系统分页文件,不关联实际文件)
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用系统分页文件
NULL, // 默认安全属性
PAGE_READWRITE, // 读写权限
0, // 高32位大小
BUF_SIZE, // 低32位大小
L"LSEDU" // 共享内存名称
);
if (hMapFile == NULL) {
cout << "创建共享内存失败,错误码:" << GetLastError() << endl;
return 1;
}
// 2. 映射到当前进程地址空间
LPVOID lpBase = MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0, BUF_SIZE
);
if (lpBase == NULL) {
cout << "映射失败,错误码:" << GetLastError() << endl;
CloseHandle(hMapFile);
return 1;
}
// 3. 写入数据
strcpy((char*)lpBase, szBuffer);
cout << "【服务器】已写入数据:" << (char*)lpBase << endl;
// 4. 等待客户端读取(按任意键退出)
cout << "按任意键退出..." << endl;
cin.get();
// 5. 清理资源
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
return 0;
}
客户端
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;
#define BUF_SIZE 1024
int main() {
// 1. 打开已存在的共享内存对象
HANDLE hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // 读写权限
FALSE, // 不继承句柄
L"LSEDU" // 共享内存名称(必须与服务器端一致)
);
if (hMapFile == NULL) {
cout << "打开共享内存失败,错误码:" << GetLastError() << endl;
return 1;
}
// 2. 映射到当前进程地址空间
LPVOID lpBase = MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0, BUF_SIZE
);
if (lpBase == NULL) {
cout << "映射失败,错误码:" << GetLastError() << endl;
CloseHandle(hMapFile);
return 1;
}
// 3. 读取数据
char szBuffer[BUF_SIZE] = { 0 };
strcpy(szBuffer, (char*)lpBase);
cout << "【客户端】读取到数据:" << szBuffer << endl;
// 4. 清理资源
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
return 0;
}
运行结果
先运行服务端的文件保持不退出,后运行客户端的文件,即可看到如下读取数据
关键注意事项
- 名称必须一致:
CreateFileMapping和OpenFileMapping使用的名称必须完全相同(包括大小写) - 先创建后打开:服务器端必须先创建共享内存,客户端才能打开
- 生命周期管理:共享内存对象的生命周期与最后一个关闭句柄的进程相关,所有进程都关闭后才会被系统销毁
- 同步问题:共享内存本身不提供同步机制,多个进程同时读写时需要配合互斥量
(Mutex)、事件(Event)等同步手段,否则会出现数据竞争
互斥量同步
如果客户端需要在服务器写入完成后再读取,可以用互斥量来同步:
服务端(创建共享内存 + 写入数据 + 互斥量同步)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;
#define BUF_SIZE 1024 // 共享内存缓冲区大小
int main() {
// 要写入共享内存的数据
char szBuffer[] = "哈哈哈,C++共享内存实战";
// ==================== 第一步:创建共享内存对象 ====================
// CreateFileMapping 参数说明:
// - INVALID_HANDLE_VALUE: 表示不关联实际文件,使用系统分页文件(纯内存共享)
// - NULL: 默认安全属性,子进程不可继承
// - PAGE_READWRITE: 内存页保护属性,允许读写
// - 0: 共享内存大小的高32位(BUF_SIZE 较小,高32位为0)
// - BUF_SIZE: 共享内存大小的低32位
// - L"LSEDU": 共享内存对象的名称(全局唯一标识,客户端通过此名称打开)
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUF_SIZE,
L"LSEDU"
);
// 创建失败则输出错误码并退出
if (hMapFile == NULL) {
cout << "创建共享内存失败,错误码:" << GetLastError() << endl;
return 1;
}
// ==================== 第二步:将共享内存映射到当前进程地址空间 ====================
// MapViewOfFile 参数说明:
// - hMapFile: 文件映射对象句柄
// - FILE_MAP_ALL_ACCESS: 访问权限,允许读写
// - 0, 0: 文件映射的偏移量(高32位和低32位),从开头映射
// - BUF_SIZE: 要映射的字节数
// 返回值:映射成功后返回指向共享内存的指针
LPVOID lpBase = MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0, BUF_SIZE
);
if (lpBase == NULL) {
cout << "映射失败,错误码:" << GetLastError() << endl;
CloseHandle(hMapFile); // 清理已创建的对象
return 1;
}
// ==================== 第三步:创建互斥量(用于进程间同步) ====================
// CreateMutex 参数说明:
// - NULL: 默认安全属性
// - TRUE: 初始状态为"已拥有"(即创建者拥有互斥量),客户端打开后会阻塞等待
// - L"DataReadyMutex": 互斥量名称(全局唯一标识)
HANDLE hMutex = CreateMutex(NULL, TRUE, L"DataReadyMutex");
if (hMutex == NULL) {
cout << "创建互斥量失败,错误码:" << GetLastError() << endl;
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
return 1;
}
// ==================== 第四步:向共享内存写入数据 ====================
// 将数据拷贝到共享内存区域(lpBase 指向共享内存的起始地址)
strcpy((char*)lpBase, szBuffer);
cout << "【服务器】已写入数据:" << (char*)lpBase << endl;
// ==================== 第五步:释放互斥量,通知客户端 ====================
// ReleaseMutex 将互斥量状态从"已拥有"改为"未拥有"
// 此时正在等待该互斥量的客户端会被唤醒,继续执行
ReleaseMutex(hMutex);
cout << "【服务器】已释放互斥量,通知客户端可以读取" << endl;
// ==================== 第六步:等待用户操作后退出 ====================
cout << "按任意键退出..." << endl;
cin.get();
// ==================== 第七步:清理资源(按创建的逆序释放) ====================
CloseHandle(hMutex); // 关闭互斥量句柄
UnmapViewOfFile(lpBase); // 取消内存映射
CloseHandle(hMapFile); // 关闭文件映射对象句柄
return 0;
}
客户端(打开共享内存 + 读取数据 + 互斥量同步)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;
#define BUF_SIZE 1024 // 共享内存缓冲区大小(需与服务器端一致)
int main() {
// ==================== 第一步:打开已存在的共享内存对象 ====================
// OpenFileMapping 参数说明:
// - FILE_MAP_ALL_ACCESS: 请求的访问权限(读写)
// - FALSE: 句柄不可被子进程继承
// - L"LSEDU": 共享内存名称(必须与服务器端 CreateFileMapping 中的名称完全一致)
HANDLE hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
L"LSEDU"
);
// 打开失败(通常是因为服务器端未运行或已退出)
if (hMapFile == NULL) {
cout << "打开共享内存失败,错误码:" << GetLastError() << endl;
return 1;
}
// ==================== 第二步:将共享内存映射到当前进程地址空间 ====================
LPVOID lpBase = MapViewOfFile(
hMapFile,
FILE_MAP_ALL_ACCESS,
0, 0, BUF_SIZE
);
if (lpBase == NULL) {
cout << "映射失败,错误码:" << GetLastError() << endl;
CloseHandle(hMapFile);
return 1;
}
// ==================== 第三步:打开互斥量 ====================
// OpenMutex 参数说明:
// - SYNCHRONIZE: 请求同步访问权限(只需等待/释放,不需要修改互斥量)
// - FALSE: 句柄不可继承
// - L"DataReadyMutex": 互斥量名称(必须与服务器端 CreateMutex 中的名称一致)
HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, L"DataReadyMutex");
if (hMutex == NULL) {
cout << "打开互斥量失败,错误码:" << GetLastError() << endl;
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
return 1;
}
// ==================== 第四步:等待服务器端通知 ====================
// WaitForSingleObject 会阻塞当前线程,直到:
// - 互斥量变为"未拥有"状态(服务器端调用了 ReleaseMutex)
// - 或者超时(INFINITE 表示永不超时)
cout << "【客户端】正在等待服务器端数据..." << endl;
WaitForSingleObject(hMutex, INFINITE);
cout << "【客户端】收到通知,开始读取数据" << endl;
// ==================== 第五步:从共享内存读取数据 ====================
char szBuffer[BUF_SIZE] = { 0 }; // 初始化为全0
strcpy(szBuffer, (char*)lpBase); // 从共享内存拷贝数据到本地缓冲区
cout << "【客户端】读取到数据:" << szBuffer << endl;
// ==================== 第六步:清理资源(按创建的逆序释放) ====================
CloseHandle(hMutex); // 关闭互斥量句柄
UnmapViewOfFile(lpBase); // 取消内存映射
CloseHandle(hMapFile); // 关闭文件映射对象句柄
return 0;
}

| 概念 | 说明 |
|---|---|
INVALID_HANDLE_VALUE |
表示不关联实际磁盘文件,使用系统分页文件实现纯内存共享 |
CreateFileMapping vs OpenFileMapping |
前者创建,后者打开;名称必须完全一致 |
MapViewOfFile |
将共享内存"映射"到进程自己的地址空间,返回一个指针,之后就像操作普通内存一样 |
CreateMutex(..., TRUE, ...) |
第二个参数 TRUE 表示创建者立即拥有互斥量,其他人打开后会阻塞 |
ReleaseMutex |
释放互斥量,唤醒等待者 |
WaitForSingleObject(..., INFINITE) |
无限等待,直到被唤醒 |
| 资源释放顺序 | 建议按创建的逆序释放:先关互斥量 → 取消映射 → 关文件映射 |
总结
使用共享内存的核心原则
适合本机进程间大量、高频的数据交换
必须配合同步机制(互斥量、事件、信号量等),否则会出现数据竞争
不适合跨机器通信,跨机器场景用 Socket 或 RPC
注意生命周期管理,避免进程异常退出导致共享内存"泄漏"
概括一句话
只要是在同一台机器上,多个进程需要频繁交换大量数据,共享内存就是最优选择。
更多推荐


所有评论(0)