C++ 共享内存如何彻底删除?

五岳凌峰 2018-03-26 12:40:04
进程M(比如M.exe)创建了两个线程,主线程A和子线程B。在函数ThreadA::CaptureImage中创建共享内存,往共享内存写入数据;在ThreadB::CaptureImage中打开共享内存,从共享内存读取数据;
HRESULT ThreadA::CaptureImage(para1,para2)
{
...
// memory size
int MemorySize = ImageWidth * ImageHeight;
// share memory name
_bstr_t csShareMemoryName = _T("CaptureImage");
//create share memory
HANDLE hShareMemoryHandle = NULL;
hShareMemoryHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, csShareMemoryName);
if (NULL == hShareMemoryHandle)
{
hShareMemoryHandle = ::CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
nInit,
MemorySize,
csShareMemoryName);
DWORD dwCurrentThreadID = GetCurrentThreadId();
CString test_CaptureImage;
test_CaptureImage.Format(_T("### [TID]:%d, memorysize=%d"), long(dwCurrentThreadID), MemorySize);
OutputDebugString(test_CaptureImage);
// Check if create share memory successfully
if (NULL == hShareMemoryHandle)
{
if (pImageData != NULL)
{
delete[] pImageData;
pImageData = NULL;
}
return E_FAIL;
}
}
// Map the sharing memory.
LPVOID pShareMemoryAddress = MapViewOfFile(
hShareMemoryHandle,
FILE_MAP_ALL_ACCESS,
nInit,
nInit,
nInit);
BYTE* pBuffer = reinterpret_cast<BYTE*>(pShareMemoryAddress);

// Fill the sharing memory.
memcpy(pBuffer, pImageData, MemorySize);
// Unmaps a mapped view of a file from the address space of the calling process.
UnmapViewOfFile(pShareMemoryAddress);

if (pImageData != NULL)
{
delete[] pImageData;
pImageData = NULL;
}
...
return S_OK;
}

HRESULT ThreadB::CaptureImage( para1,... )
{
...
// memory size
int MemorySize=GetMemorySize();
// share memory name
_bstr_t csShareMemoryName = _T("CaptureImage");
//open file mapping
HANDLE hShareMemoryHandle = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
csShareMemoryName);
if (NULL == hShareMemoryHandle)
{
return E_FAIL;
}
// Map the sharing memory.
LPVOID pShareMemoryAddress = MapViewOfFile(
hShareMemoryHandle,
FILE_MAP_READ,
nZero,
nZero,
nZero);
if (NULL == pShareMemoryAddress)
{
return E_FAIL;
}

BYTE* pBuffer = new BYTE[MemorySize];
memcpy(pBuffer, pShareMemoryAddress, MemorySize);

UnmapViewOfFile(pShareMemoryAddress);
CloseHandle(hShareMemoryHandle);
...
return S_OK;
}

问题:因为共享内存名字保持不变,当多次调用ThreadA::CaptureImage时,操作系统(或者叫内核对象?)会检查该共享内存名字是否已存在,如果存在,不再创建。 就是说,ThreadA::CaptureImage第一次被调用时,共享内存"CaptureImage"才会创建,后面再被调用,不再创建。且共享内存大小是第一次指定的大小,不会改变。假设第一次指定的大小为1000,当第2次调用ThreadA::CaptureImage时,需要的共享内存大小为4000。由于共享内存没有以4000重新创建,保持1000。当程序执行到代码行
	// Fill the sharing memory.
memcpy(pBuffer, pImageData, MemorySize);

会出现指针地址越界的情况。
考虑的解决方案如下:
方案1:根据指定大小创建共享内存,例如共享内存名字格式为CaptureImage_1000,CaptureImage_4000等。该方案简单,自己已经实现。

方案2:不修改共享内存名字。ThreadB::CaptureImage中读取共享内存数据后,把共享内存彻底删除。这样,每次调用ThreadA::CaptureImage时,
OpenFileMapping返回值为NULL,然后重新创建共享内存。通过该调用什么函数彻底删除共享内存?函数FlushViewOfFile?
如果没有删除共享内存的函数,那共享内存的生存周期和进程M相同?

方案3:不修改共享内存名字,有没有扩容的函数?就是比较前后两次指定的共享内存大小,如果本次指定的比上一次指定的大,就在上一次基础上扩大共享内存大小?

倾向用方案2。方案1虽然简单,举个极端例子,假设重复调用ThreadA::CaptureImage,10000次,每次共享内存大小都不一样,这样就得创建10000个共享内存,个人认为资源利用率较低。方案3,可能没有这样的扩容函数。 想请教大家,方案2的实现思路。谢谢
...全文
1114 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
paschen 版主 2018-03-26
  • 打赏
  • 举报
回复
通过UnmapViewOfFile + CloseHandle 删除
五岳凌峰 2018-03-26
  • 打赏
  • 举报
回复
编译环境:win10 pro + VS2017

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧