c++共享内存
c共享内存什么是共享内存共享内存是进程间通信(IPC)的一种方式允许多个进程访问同一块内存区域实现数据共享它是所有IPC方式中速度最快的因为数据不需要在进程间拷贝。API作用CreateFileMapping创建/打开一个文件映射对象共享内存OpenFileMapping打开一个已存在的文件映射对象MapViewOfFile将文件映射对象映射到当前进程的地址空间UnmapViewOfFile取消映射CloseHandle关闭句柄完整示例服务端#define_CRT_SECURE_NO_WARNINGS#includeiostream#includeWindows.husingnamespacestd;#defineBUF_SIZE1024intmain(){charszBuffer[]哈哈哈C共享内存实战;// 1. 创建共享内存对象-1 表示使用系统分页文件不关联实际文件HANDLE hMapFileCreateFileMapping(INVALID_HANDLE_VALUE,// 使用系统分页文件NULL,// 默认安全属性PAGE_READWRITE,// 读写权限0,// 高32位大小BUF_SIZE,// 低32位大小LLSEDU// 共享内存名称);if(hMapFileNULL){cout创建共享内存失败错误码GetLastError()endl;return1;}// 2. 映射到当前进程地址空间LPVOID lpBaseMapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,BUF_SIZE);if(lpBaseNULL){cout映射失败错误码GetLastError()endl;CloseHandle(hMapFile);return1;}// 3. 写入数据strcpy((char*)lpBase,szBuffer);cout【服务器】已写入数据(char*)lpBaseendl;// 4. 等待客户端读取按任意键退出cout按任意键退出...endl;cin.get();// 5. 清理资源UnmapViewOfFile(lpBase);CloseHandle(hMapFile);return0;}客户端#define_CRT_SECURE_NO_WARNINGS#includeiostream#includeWindows.husingnamespacestd;#defineBUF_SIZE1024intmain(){// 1. 打开已存在的共享内存对象HANDLE hMapFileOpenFileMapping(FILE_MAP_ALL_ACCESS,// 读写权限FALSE,// 不继承句柄LLSEDU// 共享内存名称必须与服务器端一致);if(hMapFileNULL){cout打开共享内存失败错误码GetLastError()endl;return1;}// 2. 映射到当前进程地址空间LPVOID lpBaseMapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,BUF_SIZE);if(lpBaseNULL){cout映射失败错误码GetLastError()endl;CloseHandle(hMapFile);return1;}// 3. 读取数据charszBuffer[BUF_SIZE]{0};strcpy(szBuffer,(char*)lpBase);cout【客户端】读取到数据szBufferendl;// 4. 清理资源UnmapViewOfFile(lpBase);CloseHandle(hMapFile);return0;}运行结果先运行服务端的文件保持不退出后运行客户端的文件即可看到如下读取数据关键注意事项名称必须一致CreateFileMapping和OpenFileMapping使用的名称必须完全相同包括大小写先创建后打开服务器端必须先创建共享内存客户端才能打开生命周期管理共享内存对象的生命周期与最后一个关闭句柄的进程相关所有进程都关闭后才会被系统销毁同步问题共享内存本身不提供同步机制多个进程同时读写时需要配合互斥量Mutex、事件Event等同步手段否则会出现数据竞争互斥量同步如果客户端需要在服务器写入完成后再读取可以用互斥量来同步服务端创建共享内存 写入数据 互斥量同步#define_CRT_SECURE_NO_WARNINGS#includeiostream#includeWindows.husingnamespacestd;#defineBUF_SIZE1024// 共享内存缓冲区大小intmain(){// 要写入共享内存的数据charszBuffer[]哈哈哈C共享内存实战;// 第一步创建共享内存对象 // CreateFileMapping 参数说明// - INVALID_HANDLE_VALUE: 表示不关联实际文件使用系统分页文件纯内存共享// - NULL: 默认安全属性子进程不可继承// - PAGE_READWRITE: 内存页保护属性允许读写// - 0: 共享内存大小的高32位BUF_SIZE 较小高32位为0// - BUF_SIZE: 共享内存大小的低32位// - LLSEDU: 共享内存对象的名称全局唯一标识客户端通过此名称打开HANDLE hMapFileCreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,BUF_SIZE,LLSEDU);// 创建失败则输出错误码并退出if(hMapFileNULL){cout创建共享内存失败错误码GetLastError()endl;return1;}// 第二步将共享内存映射到当前进程地址空间 // MapViewOfFile 参数说明// - hMapFile: 文件映射对象句柄// - FILE_MAP_ALL_ACCESS: 访问权限允许读写// - 0, 0: 文件映射的偏移量高32位和低32位从开头映射// - BUF_SIZE: 要映射的字节数// 返回值映射成功后返回指向共享内存的指针LPVOID lpBaseMapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,BUF_SIZE);if(lpBaseNULL){cout映射失败错误码GetLastError()endl;CloseHandle(hMapFile);// 清理已创建的对象return1;}// 第三步创建互斥量用于进程间同步 // CreateMutex 参数说明// - NULL: 默认安全属性// - TRUE: 初始状态为已拥有即创建者拥有互斥量客户端打开后会阻塞等待// - LDataReadyMutex: 互斥量名称全局唯一标识HANDLE hMutexCreateMutex(NULL,TRUE,LDataReadyMutex);if(hMutexNULL){cout创建互斥量失败错误码GetLastError()endl;UnmapViewOfFile(lpBase);CloseHandle(hMapFile);return1;}// 第四步向共享内存写入数据 // 将数据拷贝到共享内存区域lpBase 指向共享内存的起始地址strcpy((char*)lpBase,szBuffer);cout【服务器】已写入数据(char*)lpBaseendl;// 第五步释放互斥量通知客户端 // ReleaseMutex 将互斥量状态从已拥有改为未拥有// 此时正在等待该互斥量的客户端会被唤醒继续执行ReleaseMutex(hMutex);cout【服务器】已释放互斥量通知客户端可以读取endl;// 第六步等待用户操作后退出 cout按任意键退出...endl;cin.get();// 第七步清理资源按创建的逆序释放 CloseHandle(hMutex);// 关闭互斥量句柄UnmapViewOfFile(lpBase);// 取消内存映射CloseHandle(hMapFile);// 关闭文件映射对象句柄return0;}客户端打开共享内存 读取数据 互斥量同步#define_CRT_SECURE_NO_WARNINGS#includeiostream#includeWindows.husingnamespacestd;#defineBUF_SIZE1024// 共享内存缓冲区大小需与服务器端一致intmain(){// 第一步打开已存在的共享内存对象 // OpenFileMapping 参数说明// - FILE_MAP_ALL_ACCESS: 请求的访问权限读写// - FALSE: 句柄不可被子进程继承// - LLSEDU: 共享内存名称必须与服务器端 CreateFileMapping 中的名称完全一致HANDLE hMapFileOpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,LLSEDU);// 打开失败通常是因为服务器端未运行或已退出if(hMapFileNULL){cout打开共享内存失败错误码GetLastError()endl;return1;}// 第二步将共享内存映射到当前进程地址空间 LPVOID lpBaseMapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,BUF_SIZE);if(lpBaseNULL){cout映射失败错误码GetLastError()endl;CloseHandle(hMapFile);return1;}// 第三步打开互斥量 // OpenMutex 参数说明// - SYNCHRONIZE: 请求同步访问权限只需等待/释放不需要修改互斥量// - FALSE: 句柄不可继承// - LDataReadyMutex: 互斥量名称必须与服务器端 CreateMutex 中的名称一致HANDLE hMutexOpenMutex(SYNCHRONIZE,FALSE,LDataReadyMutex);if(hMutexNULL){cout打开互斥量失败错误码GetLastError()endl;UnmapViewOfFile(lpBase);CloseHandle(hMapFile);return1;}// 第四步等待服务器端通知 // WaitForSingleObject 会阻塞当前线程直到// - 互斥量变为未拥有状态服务器端调用了 ReleaseMutex// - 或者超时INFINITE 表示永不超时cout【客户端】正在等待服务器端数据...endl;WaitForSingleObject(hMutex,INFINITE);cout【客户端】收到通知开始读取数据endl;// 第五步从共享内存读取数据 charszBuffer[BUF_SIZE]{0};// 初始化为全0strcpy(szBuffer,(char*)lpBase);// 从共享内存拷贝数据到本地缓冲区cout【客户端】读取到数据szBufferendl;// 第六步清理资源按创建的逆序释放 CloseHandle(hMutex);// 关闭互斥量句柄UnmapViewOfFile(lpBase);// 取消内存映射CloseHandle(hMapFile);// 关闭文件映射对象句柄return0;}概念说明INVALID_HANDLE_VALUE表示不关联实际磁盘文件使用系统分页文件实现纯内存共享CreateFileMappingvsOpenFileMapping前者创建后者打开名称必须完全一致MapViewOfFile将共享内存映射到进程自己的地址空间返回一个指针之后就像操作普通内存一样CreateMutex(..., TRUE, ...)第二个参数TRUE表示创建者立即拥有互斥量其他人打开后会阻塞ReleaseMutex释放互斥量唤醒等待者WaitForSingleObject(..., INFINITE)无限等待直到被唤醒资源释放顺序建议按创建的逆序释放先关互斥量 → 取消映射 → 关文件映射总结使用共享内存的核心原则适合本机进程间大量、高频的数据交换必须配合同步机制互斥量、事件、信号量等否则会出现数据竞争不适合跨机器通信跨机器场景用Socket或RPC注意生命周期管理避免进程异常退出导致共享内存泄漏概括一句话只要是在同一台机器上多个进程需要频繁交换大量数据共享内存就是最优选择。