c++ - 如何通过文件映射对象重新映射共享内存的 View ?

标签 c++ winapi shared-memory file-mapping

比如说,如果我有一个共享文件映射对象:

HANDLE hFileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
    PAGE_READWRITE, 0, 0x8000, L"MyObjectName");

我得到了其中的一小部分供查看,如下所示:

BYTE* pData = (BYTE*)::MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0x10);
if(!pData) return false;   //fail
DWORD dwcbFullSize = *(DWORD*)(pData + 0xC);

那么如果我需要分配更多数据,是否可以在不先取消映射 pData 的情况下再次调用 MapViewOfFile

BYTE* pFullData = (BYTE*)::MapViewOfFile(hFileMapping,
      FILE_MAP_READ, 0, 0, dwcbFullSize);

附言。我的目标是不将 CPU 周期浪费在映射整个 32K 共享内存段上,而我可能需要读取的可能远少于此。

最佳答案

为此任务需要使用 SEC_RESERVE创建文件映射时的属性(部分)

If the file mapping object is backed by the operating system paging file (the hfile parameter is INVALID_HANDLE_VALUE), specifies that when a view of the file is mapped into a process address space, the entire range of pages is reserved for later use by the process rather than committed. Reserved pages can be committed in subsequent calls to the VirtualAlloc function. After the pages are committed, they cannot be freed or decommitted with the VirtualFree function. This attribute has no effect for file mapping objects that are backed by executable image files or data files (the hfile parameter is a handle to a file). SEC_RESERVE cannot be combined with SEC_COMMIT.

因此在使用 SEC_RESERVE 属性创建部分后需要调用一次 MapViewOfFile - 此调用不保留内存范围但不提交页面。提交页面需要调用 VirtualAlloc。最后我们可以通过调用 UnmapViewOfFile

释放所有内存
void DoDemo(ULONG cb)
{
    if (!cb)
    {
        return;
    }

    SYSTEM_INFO si;
    GetSystemInfo(&si);

    cb = (cb + (si.dwPageSize - 1)) & ~(si.dwPageSize - 1);

    if (HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, 0,
        PAGE_READWRITE|SEC_RESERVE, 0, cb, L"MyObjectName"))
    {
        // reserve address space with PAGE_READWRITE initial protection

        PVOID BaseAddress = MapViewOfFile(hFileMapping, 
            FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, cb);

        // hFileMapping no more need
        CloseHandle(hFileMapping);

        if (BaseAddress)
        {
            // check, for test only
            ::MEMORY_BASIC_INFORMATION mbi;
            if (VirtualQuery(BaseAddress, &mbi, sizeof(mbi)) < sizeof(mbi) ||
                mbi.Type != MEM_MAPPED || mbi.State != MEM_RESERVE)
            {
                __debugbreak();
            }

            // map page by page
            PBYTE pb = (BYTE*)BaseAddress;
            do 
            {
                if (!VirtualAlloc(pb, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE))
                {
                    GetLastError();
                    break;
                }
                *pb = '*';//write something
            } while (pb += si.dwPageSize, cb -= si.dwPageSize);

            //unmap all
            UnmapViewOfFile(BaseAddress);
        }
    }
}

然而,所有这些只对大尺寸部分有意义。对于 32kb(小尺寸),最好的方法是在一次调用中映射所有页面

关于c++ - 如何通过文件映射对象重新映射共享内存的 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46995494/

相关文章:

c++ - 向静态控件发送文本

Java 并发 - 为什么同步 setter(而不是 getter)不能使类线程安全?

android - 与 JNI 的共享库 : how to maintain global variables?

python - 无法导入名称共享内存

c++ - 虚函数表指针的大小是多少?

c++ - 将 %E6%B0%94%E6%97%8B%E5%93%88%E5%88%A9.txt 解码为有效字符串

c# - 将 C# 字符串传递给 C++,并将 C++ 结果(字符串、char*.. 任何)传递给 C#

c++ - 静态(可能是 constexpr)数据成员 l​​ambda

c++ - 仅禁用 win32 ListView 中的特定列表项

c++ - CreateSymbolicLink 相当于 “mklink/J” ?