C++ 如何通过文件映射对象重新映射共享内存的视图?
例如,如果我有一个共享文件映射对象:C++ 如何通过文件映射对象重新映射共享内存的视图?,c++,winapi,shared-memory,file-mapping,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)
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);
那么,如果需要分配更多数据,是否可以在不首先取消映射的情况下再次调用MapViewOfFile
BYTE* pFullData = (BYTE*)::MapViewOfFile(hFileMapping,
FILE_MAP_READ, 0, 0, dwcbFullSize);
另外,我的目标是不浪费CPU周期来映射整个32K共享内存段,而我可能需要读取的数据可能远小于此值。对于此任务,在创建文件映射时需要使用属性(第节)
如果操作系统分页支持文件映射对象
file(hfile参数无效\u HANDLE\u值)指定
当文件的视图映射到进程地址空间时
整个页面范围保留供流程稍后使用,而不是
而不是承诺。保留页可以在后续调用中提交到
VirtualAlloc
功能。提交页面后,它们将无法
可以使用VirtualFree
功能释放或解除启用。这个属性
对可执行文件支持的文件映射对象无效
图像文件或数据文件(hfile参数是文件的句柄)。
秒保留不能与秒提交相结合
因此,在使用SEC_RESERVE
属性创建节后,需要一次调用MapViewOfFile
——此调用不保留内存范围,但不提交页面。对于提交页面,需要调用VirtualAlloc
。最后,我们可以通过调用unmpviewoffile
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);
}
}
}
void DoDemo(乌龙cb)
{
如果(!cb)
{
返回;
}
系统信息系统;
GetSystemInfo&si;
cb=(cb+(si.dwPageSize-1))&~(si.dwPageSize-1);
如果(HANDLE hFileMapping=CreateFileMapping)(无效的句柄值,0,
第|页读写|第|页保留,0,cb,L“MyObjectName”))
{
//保留地址空间,具有页\读写初始保护
PVOID BaseAddress=MapViewOfFile(hFileMapping,
文件映射读取文件映射写入,0,0,cb);
//HFILE映射不再需要了
CloseHandle(hFileMapping);
if(基地址)
{
//检查,仅用于测试
::存储器基本信息mbi;
if(VirtualQuery(BaseAddress,&mbi,sizeof(mbi))
然而,所有这些都只适用于大尺寸截面。对于32kb(极小的大小),最好只需在一次调用中映射所有页面对于此任务,在创建文件映射时需要使用属性(第节)
如果操作系统分页支持文件映射对象
file(hfile参数无效\u HANDLE\u值)指定
当文件的视图映射到进程地址空间时
整个页面范围保留供流程稍后使用,而不是
而不是承诺。保留页可以在后续调用中提交到
VirtualAlloc
功能。提交页面后,它们将无法
可以使用VirtualFree
功能释放或解除启用。这个属性
对可执行文件支持的文件映射对象无效
图像文件或数据文件(hfile参数是文件的句柄)。
秒保留不能与秒提交相结合
因此,在使用SEC_RESERVE
属性创建节后,需要一次调用MapViewOfFile
——此调用不保留内存范围,但不提交页面。对于提交页面,需要调用VirtualAlloc
。最后,我们可以通过调用unmpviewoffile
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);
}
}
}
void DoDemo(乌龙cb)
{
如果(!cb)
{
返回;
}
系统信息系统;
GetSystemInfo&si;
cb=(cb+(si.dwPageSize-1))&~(si.dwPageSize-1);
如果(HANDLE hFileMapping=CreateFileMapping)(无效的句柄值,0,
第|页读写|第|页保留,0,cb,L“MyObjectName”))
{
//保留地址空间,具有页\读写初始保护
PVOID BaseAddress=MapViewOfFile(hFileMapping,
文件映射读取文件映射写入,0,0,cb);
//HFILE映射不再需要了
CloseHandle(hFileMapping);
if(基地址)
{
//检查,仅用于测试
::存储器基本信息mbi;
if(VirtualQuery(BaseAddress,&mbi,sizeof(mbi))
然而,所有这些都只适用于大尺寸截面。对于32kb(很小的尺寸),最好只需在一次调用中映射所有页面我可能误解了这个问题,所以请耐心等待。我已经决定用一些wor更清楚地展示我在评论中所说的话
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#pragma comment(lib, "user32.lib")
#define BUF_SIZE 256
TCHAR szName[] = TEXT("Global\\MyFileMappingObject");
int mapDataAtOffset(DWORD offset, size_t bytesToRead, LPVOID* outData, LPVOID* outMapAddress);
int _tmain()
{
LPCTSTR pBuf;
LPVOID outMapAddress = nullptr;
LPVOID outMapAddress2 = nullptr;
auto ret = mapDataAtOffset(0, 8, (LPVOID*)&pBuf, &outMapAddress);
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
ret = mapDataAtOffset(8, 8, (LPVOID*)&pBuf, &outMapAddress2);
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
if(outMapAddress)UnmapViewOfFile(outMapAddress);
if (outMapAddress2)UnmapViewOfFile(outMapAddress2);
return 0;
}
int mapDataAtOffset(DWORD offset, size_t bytesToRead, LPVOID* outData, LPVOID* outMapAddress) {
HANDLE hMapFile; // handle for the file's memory-mapped region
BOOL bFlag; // a result holder
DWORD dBytesWritten; // number of bytes written
DWORD dwFileMapSize; // size of the file mapping
DWORD dwMapViewSize; // the size of the view
DWORD dwFileMapStart; // where to start the file map view
DWORD dwSysGran; // system allocation granularity
SYSTEM_INFO SysInfo; // system information; used to get granularity
LPVOID lpMapAddress; // pointer to the base address of the
// memory-mapped region
char * pData; // pointer to the data
int i; // loop counter
int iData; // on success contains the first int of data
int iViewDelta; // the offset into the view where the data
//shows up
DWORD FILE_MAP_START = offset;
// Get the system allocation granularity.
GetSystemInfo(&SysInfo);
dwSysGran = SysInfo.dwAllocationGranularity;
// Now calculate a few variables. Calculate the file offsets as
// 64-bit values, and then get the low-order 32 bits for the
// function calls.
// To calculate where to start the file mapping, round down the
// offset of the data into the file to the nearest multiple of the
// system allocation granularity.
dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
_tprintf(TEXT("The file map view starts at %ld bytes into the file.\n"),
dwFileMapStart);
// Calculate the size of the file mapping view.
dwMapViewSize = (FILE_MAP_START % dwSysGran) + bytesToRead;
_tprintf(TEXT("The file map view is %ld bytes large.\n"),
dwMapViewSize);
// How large will the file mapping object be?
dwFileMapSize = FILE_MAP_START + bytesToRead;
_tprintf(TEXT("The file mapping object is %ld bytes large.\n"),
dwFileMapSize);
// The data of interest isn't at the beginning of the
// view, so determine how far into the view to set the pointer.
iViewDelta = FILE_MAP_START - dwFileMapStart;
_tprintf(TEXT("The data is %d bytes into the view.\n"),
iViewDelta);
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
// Map the view and test the results.
lpMapAddress = MapViewOfFile(hMapFile, // handle to
// mapping object
FILE_MAP_ALL_ACCESS, // read/write
0, // high-order 32
// bits of file
// offset
dwFileMapStart, // low-order 32
// bits of file
// offset
dwMapViewSize); // number of bytes
// to map
if (lpMapAddress == NULL)
{
_tprintf(TEXT("lpMapAddress is NULL: last error: %d\n"), GetLastError());
return 3;
}
// Calculate the pointer to the data.
pData = (char *)lpMapAddress + iViewDelta;
*outData = pData;
*outMapAddress = lpMapAddress;
CloseHandle(hMapFile); // close the file mapping object, doesn't matter as long as view is still mapped
return 0;
}