【问题标题】:Safely growing a memory mapped file in C++ application在 C++ 应用程序中安全地增长内存映射文件
【发布时间】:2013-02-24 02:11:01
【问题描述】:

我有一个最初在 Visual C++ 6.0 中构建的古老 C++ 应用程序,它使用一个非常复杂的共享内存 DLL 在大约 8 个 EXE 和 DLL 之间共享数据,这些 EXE 和 DLL 都有一个可以被一个或两个字典替换的值池键是字符串,值是记录。该应用程序是多线程和多进程的。有三个主要的可执行文件读取和写入共享内存区域,其中几个可执行文件具有 3 个或更多线程,这些线程读取/写入或“排队”信息到这个池化内存区域。大约几百个地方,__try__except 的结构化异常处理 (SEH) 用于过滤异常,并尝试通过调整共享内存的大小来处理访问冲突,这些共享内存位于由名为 @ 的类管理的段中987654324@ 表示可增长的内存映射文件。

这里显示了最重要的细节,因为我找不到任何关于所使用技术的有凝聚力的文档来源,或者它的安全性和适用性。实验上我发现这个库在 1998 年在单核系统上运行得不是很好,它在运行 windows XP 的单核虚拟机上有点工作,在现代 2+ ghz multi 上它根本不工作- 2013 年的核心 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),以及手动防止并发问题,使用同步/互斥/临界区或其他适当的线程安全结构。

我想知道是否已经有一些线程安全的内存字典类型可以替换所有这些类型。即使在上面这个比这个古老的 shared-memory-library-for-visual-C++-6 的代码还不到 1% 的 sn-p 中,也有让我不寒而栗的东西。例如,提高线程优先级作为避免死锁、竞争条件和一般损坏的策略。也许这曾经使这段代码在 33 mhz 的 80486 CPU 上停止崩溃。 颤抖。

我有代码在 Visual C++ 6.0 中构建和运行,它的一个分支也在 Visual C++ 2008 中运行,我可能会在 Visual C++ 2010 中运行它。我可以使用什么来给我字典语义,共享跨进程内存,稳定可靠?

更新 “字典”是指 Python 中已知的字典数据类型,在某些地方和其他地方(如 C++ 标准库中)也称为“键/值存储” ),它被称为std::map。讨论此问题的 Boost 文档是 here.

【问题讨论】:

  • 仅此一次尝试就值得投票。
  • 有什么理由不使用带有 CreateMutex 的“真实” MapViewOfFile 共享内存进行同步?
  • 这如何帮助我增加内存映射文件?

标签: c++ winapi visual-studio-2008 shared-memory visual-c++-6


【解决方案1】:

听起来你应该看看Boost Interprocess。您可以使用它在共享内存中拥有类似std::map 的对象等等。我上次使用它已经有好几年了,所以不能详细说明,但是库文档很好并且有大量示例,它应该可以让你在 30 分钟内完成。

【讨论】:

  • Boost 进程间看起来不错。虽然文档代码示例可以构建得更好一点:stackoverflow.com/questions/15314726/…
  • @WarrenP:嗯,它是免费和开源的,很难抱怨。我相信您的贡献将不胜感激:)
  • 在 windows 上它似乎使用文件而不是 CreateMutex,因此我上次使用它时性能很差..
猜你喜欢
  • 2011-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-28
  • 1970-01-01
  • 2016-12-08
  • 2013-02-17
  • 1970-01-01
相关资源
最近更新 更多