比如说,如果我有一个共享文件映射对象:
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 theVirtualFree
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/