SetEndOfFile 错误 1224:ERROR_USER_MAPPED_FILE,即使文件映射成功关闭

问题描述

我正在编写一个程序,它使用文件映射从文件中注销。
当我想读取日志时,调用 Logger::Destroy() 以便将写入文件映射视图的内容刷新到物理文件代码如下:

int Logger::Destroy() {
    if (m_lpMapAddress) {
        auto bRet = UnmapViewOfFile(m_lpMapAddress);
        // succeed
    }

    if (m_hMapFile) {
        auto bRet = CloseHandle(m_hMapFile);
        // succeed
        m_hMapFile = NULL;
    }

    int nSize = m_lpCurAddress - m_lpMapAddress;
    if (nSize > 0
        && nSize < (1024 * 1024 * 16 * 2))
    {
        DWORD dwPtr = SetFilePointer(m_hFile,nSize,FILE_BEGIN);

        ///// Succeed
        // if (dwPtr == INVALID_SET_FILE_POINTER)
        //  DbgViewOut(__FUNCTION__ " SetFilePointer error: %d \n",GetLastError());

        //// Error occurs :  "SetEndOfFile returned : 0 1224"
        BOOL bRet = SetEndOfFile(m_hFile);
        DbgViewOut(__FUNCTION__ " SetEndOfFile returned : %d %d\n",bRet,GetLastError()); 
    
        ....
    }

    m_lpMapAddress = m_lpCurAddress = NULL;

    return 0;
}

问题SetEndOfFile()ERROR_USER_MAPPED_FILE 失败,即使 CloseHandle(m_hMapFile) 成功。 所以我用谷歌搜索了微软关于文件映射的手册,并对其中的一些进行了评论

https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle

即使文件视图仍然打开,关闭文件映射句柄也能成功。有关更多信息,请参阅关闭文件映射对象。 >

https://docs.microsoft.com/en-us/windows/win32/memory/closing-a-file-mapping-object

当每个进程完成使用文件映射对象并取消映射所有视图时,它必须通过调用 CloseHandle 关闭文件映射对象的句柄和磁盘上的文件即使存在仍然打开的文件视图,对 CloseHandle 的这些调用也会成功。但是,保留文件视图映射会导致内存泄漏。

它说我无法相信 CloseHandle() 的结果。
我找不到解决方案。

谁能帮帮我?谢谢。


补充:我在Logger::Destroy()调用std::lock_guard<std::mutex>,这会不会影响到麻烦?

:我已经测试过了,锁定不会影响它。


更新:我已阅读When error 1224: ERROR_USER_MAPPED_FILE occurs?。而且我认为没有太大的区别。 我附加了初始化文件映射的 Logger::Initialize() 代码
而且,Logger::Initialize()Logger::Destroy() 都在同一个进程和线程中,不需要与其他人共享。

int Logger::Initialize()
{
  m_hFile = CreateFileA(
      m_zFileName.c_str(),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_norMAL,NULL);

  if (m_hFile == INVALID_HANDLE_VALUE) {
      DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n",GetLastError());
      return -1;
  }

  m_hMapFile = CreateFileMappingA(
      m_hFile,PAGE_READWRITE,1024 * 1024 * 16 * 2,m_zMapKey.c_str());

  if (!m_hMapFile) {
      DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n",GetLastError());
      return -1;
  }

  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE,TRUE,m_zMapKey.c_str());
  if (m_hMapFile == NULL) {
      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n",GetLastError());
      return -1;
  }

  m_lpMapAddress = (BYTE*)MapViewOfFile(
      m_hMapFile              // handle to mapping object,FILE_MAP_ALL_ACCESS   // read/write,0                 // high-order 32 bits of file offset,0                 // low-order 32 bits of file offset,0);                // number of bytes
  if (m_lpMapAddress == NULL) {
      DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n",GetLastError());
      return -1;
  }

  m_lpCurAddress = m_lpMapAddress;

  return 0;
}

解决方法

我会回答我自己的问题。

问题是我在OpenFileMappingA()之后调用了CreateFileMappingA(),所以m_hMapFile返回的CreateFileMappingA()泄漏了。 我删除了 OpenFileMappingA(),问题就消失了。

我曾经知道它必须在创建句柄后打开一次,几个月前我曾经在进程之间的内存共享中这样做。 但是在这次争论中,我意识到创建后打开句柄是不必要的。

非常感谢@RemyLebeau 的详细建议。

int Logger::Initialize()
{
    m_hFile = CreateFileA(
        m_zFileName.c_str(),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

    if (m_hFile == INVALID_HANDLE_VALUE) {
        DbgViewOut(__FUNCTION__  " CreateFileA error: %d \n",GetLastError());
        return -1;
    }


    m_hMapFile = CreateFileMappingA(
        m_hFile,PAGE_READWRITE,LINM_LOGGER_FILE_MAXSIZE * 2,m_zMapKey.c_str());

    if (!m_hMapFile) {
        DbgViewOut(__FUNCTION__  " CreateFileMapping error: %d \n",GetLastError());
        return -1;
    }

//// This was the solution - CreateFileMappingA & OpenFileMappingA mustn't be used for same process or thread.
//
//  m_hMapFile = OpenFileMappingA(FILE_MAP_WRITE,TRUE,m_zMapKey.c_str());
//  if (m_hMapFile == NULL) {
//      DbgViewOut(__FUNCTION__ " OpenFileMapping error: %d \n",GetLastError());
//      return -1;
//  }

    m_lpMapAddress = (BYTE*)MapViewOfFile(
        m_hMapFile              // handle to mapping object,FILE_MAP_ALL_ACCESS   // read/write,0                 // high-order 32 bits of file offset,0                 // low-order 32 bits of file offset,0);                // number of bytes
    if (m_lpMapAddress == NULL) {
        DbgViewOut(__FUNCTION__ " MapViewOfFile error: %d \n",GetLastError());
        return -1;
    }

    m_lpCurAddress = m_lpMapAddress;

    return 0;
}