在c++应用程序中安全地增长内存映射文件
Safely growing a memory mapped file in C++ application
我有一个古老的c++应用程序,最初是在Visual c++ 6.0中构建的,它使用一个非常复杂的共享内存DLL在大约8个exe和DLL之间共享数据,这些DLL都有一个值池,可以用一个或两个字典替换,其中字符串为键,记录为值。该应用程序是多线程和多进程的。有三个主可执行程序对共享内存区域进行读写,其中一些可执行程序有3个或更多的线程对这个池内存区域进行读写或"排队"信息。大约几百个地方,__try
和__except
的结构化异常处理(SEH)被用来过滤异常,并试图通过调整共享内存的大小来处理访问违规,这些共享内存由一个叫做CGMMF
的类管理,这意味着可增长的内存映射文件。
这里显示了最重要的细节,因为我找不到任何关于使用中的技术的文档来源,或者它的安全性和适用性。通过实验,我发现这个库在1998年的单核系统上运行得不是很好,它在运行windows XP的单核虚拟机上运行得很好,并且它在2013年的现代2+ ghz多核windows 7 64位系统上根本不起作用。我在试着修理或更换它。
#define ResAddrSpace(pvAddress, dwSize)
(m_hFileMapRes = CreateFileMapping(HFILE_PAGEFILE, &m_SecAttr,
PAGE_READWRITE| SEC_RESERVE, 0, dwSize, m_szRegionName),
(m_hFileMapRes == NULL) ? NULL :
MapViewOfFileEx(m_hFileMapRes, FILE_MAP_ALL_ACCESS, 0, 0, dwSize, 0))
void CGmmf::Create(void)
{
DWORD dwMaxRgnSize;
if (Gsinf.dwAllocationGranularity == 0)
{
GetSystemInfo(&Gsinf);
}
m_dwFileSizeMax = RoundUp(m_dwFileSizeMax, Gsinf.dwAllocationGranularity);
m_dwFileGrowInc = RoundUp(m_dwFileGrowInc, Gsinf.dwAllocationGranularity);
dwMaxRgnSize = m_dwFileSizeMax + m_dwOverrunBuf;
m_pbFile = (PBYTE)ResAddrSpace(NULL, dwMaxRgnSize);
Adjust(m_dwFileSizeNow);
}
void CGmmf::Adjust(IN DWORD dwDiskFileNow)
{
int nThreadPriority;
__try
{
//
// Boost our thread's priority so that another thread is
// less likely to use the same address space while
// we're changing it.
//
nThreadPriority = GetThreadPriority(GetCurrentThread());
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
//
// Restore the contents with the properly adjusted lengths
//
Construct(dwDiskFileNow);
}
__finally
{
//
// Make sure that we always restore our priority class and thread
// priority so that we do not continue to adversely affect other
// threads in the system.
//
SetThreadPriority(GetCurrentThread(), nThreadPriority);
}
}
void CGmmf::Construct(IN DWORD dwDiskFileNow)
{
DWORD dwDiskFileNew = RoundUp(dwDiskFileNow, m_dwFileGrowInc),
dwStatus = ERROR_SUCCESS;
PBYTE pbTemp;
if (dwDiskFileNew > 0)
{
//
// Grow the MMF by creating a new file-mapping object.
//
// use VirtualAlloc() here to commit
// the requested memory: VirtualAlloc will not fail
// even if the memory block is already committed:
pbTemp = (PBYTE)VirtualAlloc(m_pbFile,dwDiskFileNew,MEM_COMMIT,PAGE_READWRITE);
if(NULL == pbTemp)
{
LogError(GetLastError(), MEM_CREATE_MMF, m_szRegionName);
//
// File-mapping could not be created, the disk is
// probably full.
//
RaiseException(EXCEPTION_GMMF_DISKFULL,
EXCEPTION_NONCONTINUABLE,
0,
NULL);
}
//
// Check to see if our region has been corrupted
// by another thread.
//
if (pbTemp != m_pbFile)
{
RaiseException(EXCEPTION_GMMF_CORRUPTEDRGN,
EXCEPTION_NONCONTINUABLE,
0,
NULL);
}
}
}
到目前为止,我替换它的选项包括尝试用DCOM
(进程COM外)和COM
(进程COM内)替换所有共享内存,适当地替换到内存映射文件的地方,并手动防止并发问题,使用同步/互斥/临界区或其他线程安全的结构。
我想知道是否已经有一些线程安全的内存字典类型,我可以替换所有这些。即使在上面的代码片段中(不到这个古老的visual c++ -6共享内存库代码的1%),也有一些东西让我不寒而栗。例如,提高线程优先级作为避免死锁、竞争条件和一般损坏的策略。也许这曾经使这段代码在33兆赫的80486 CPU上停止崩溃。不寒而栗。
我在Visual c++ 6.0中构建和运行代码,它的一个分支也在Visual c++ 2008中运行,我可能会在Visual c++ 2010中运行它。我可以使用什么来提供字典语义、跨进程共享内存,并且稳定可靠?
Update这里的"字典"是指Python中已知的字典数据类型,在某些地方也称为"键/值存储",而在其他地方(如c++标准库),它被称为std::map
。这里是讨论这个问题的Boost文档
听起来你应该看看Boost Interprocess。您可以使用它在共享内存中拥有类似std::map
的对象等等。我上次使用它已经有好几年了,所以不能讲太多细节,但是库文档很好,有大量的例子,应该可以让你在30分钟内上手。
- 添加静态constexpr成员是否会更改结构/类的内存映射
- C/C++ - 查询平台相关的换行符(用于内存映射文件)
- 字符串共享内存映射的向量
- 确保内存映射页位于内存中
- 我可以将新的 std::tuple 放入内存映射区域,并在以后读回吗?
- 内存映射文件访问非常慢
- 内存映射C++中的流数据
- 我正在尝试创建一个C++映射,该映射在boost内存映射文件中具有向量值
- 内存映射区域初始数据
- 内存映射 IO 概念详细信息
- 为什么 du -sh 输出错误大小的内存映射文件
- 您可以将C 对象映射到内存映射的外围设备吗?
- 将 Android 内存映射到具有零拷贝的 GraphicBuffer
- 在内存映射时写入内存映射的文件
- 如何使用 Boost 内存映射解析 C++ 中的 CSV?
- Growing Boost.使用单个写入器的进程间内存映射文件
- 调整窗口内存映射文件的大小,而不会使指针失效
- Winapi:是否需要在可执行内存映射的文件上调用FlushInstructionCache
- 与从C++到C#的内存映射文件共享链式结构
- 在 C++ 和 C# 之间共享内存映射文件结构