title: Safely growing a memory mapped file in C++ application
body: <p>I have an ancient C++ application originally built in Visual C++ 6.0, that uses a very complex shared-memory DLL to share data among about 8 EXEs and DLLs that all have a pool of values that could be replaced by one or two dictionaries with Strings for the keys, and records for the values.  The application is multi-threaded and multi-process.  There are three primary executables reading and writing into the shared memory area, and several of the executables have 3 or more threads that read/write or "queue" information into this pooled memory area.   About a few hundred places, Structured Exception Handling (SEH) of the <code>__try</code> and <code>__except</code> is used to filter exceptions, and to try to handle Access Violations by resizing the shared memory, which are in segments managed by a class called <code>CGMMF</code> which means growable memory mapped file.</p>
  
  <p>The most salient details are shown here because I cannot find any cohesive source of documentation on the technique in use, or it's safety and suitability.  Experimentally I have found that this library didn't work very well on a single core system in 1998, it works somewhat on a single-core virtual machine running windows XP, and that it doesn't work at all on modern 2+ ghz multi-core Windows 7 64-bit systems in 2013. I'm trying to repair it or replace it.  </p>
  
  <pre><code>#define ResAddrSpace(pvAddress, dwSize)  \
     (m_hFileMapRes = CreateFileMapping(HFILE_PAGEFILE, &amp;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(&amp;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 &gt; 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);
          }
      }
  }
  </code></pre>
  
  <p>So far my options for replacing it include attempting to replace all the shared memory with <code>DCOM</code> (out of process COM) and <code>COM</code> (in process COM) as appropriate to the places where the memory mapped files, and to guard against concurrency issues by hand, using synchronization/mutex/criticalsection or other threadsafe constructs as appropriate.</p>
  
  <p>I want to know if there is already some thread-safe memory-dictionary type I could replace all of this with.  Even in the above snippet which is less than 1% of the code of this ancient shared-memory-library-for-visual-C++-6, there are things that make me shudder. For example, raising thread priority as a strategy for avoiding deadlocks, race conditions and general corruption.  Maybe that used to make this code stop crashing quite so much on an 80486 CPU at 33 mhz. <em>Shudder.</em></p>
  
  <p>I have the code building and running in Visual C++ 6.0 and also a branch of it runs in Visual C++ 2008, and I could probably get it going in Visual C++ 2010.  What could I use that would give me dictionary semantics, shared memory across processes, and is stable and reliable?</p>
  
  <p><strong>Update</strong> By "dictionary" I mean the dictionary datatype as known in Python, which is also called a "key/value store" in some places, and in others (like in the C++ standard library), it's known as <code>std::map</code>.   Boost documentation that discusses this is <a href="http://www.boost.org/doc/libs/1_53_0/doc/html/interprocess/managed_memory_segments.html#interprocess.managed_memory_segments.managed_mapped_files" rel="nofollow">here.</a></p>