On Ring Buffer's Wikipedia entry, there's example code showing a hack for UNIX systems whereby the adjacent virtual memory to a piece of memory is mapped to the same phbysical memory, thus implementing a ring buffer without the need for any memcpy, etc. I was wondering if there's a way to so something similar in Windows?
Thanks, Fraser
I didn't really follow all the details of the example in wikipedia. With that in mind, you map memory in Windows using CreateFileMapping and MapViewOfFile, however MapViewOfFile does not allow you to specify a base address for the mapping. MapViewOfFileEx can be used to specify a base address so maybe you could use a similar technique.
I don't have any way of telling if this would actually work:
// determine valid buffer size
SYSTEM_INFO info;
GetSystemInfo(&info);
// note that the base address must be a multiple of the allocation granularity
DWORD bufferSize=info.dwAllocationGranularity;
HANDLE hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
bufferSize*2,
L"Mapping");
BYTE *pBuf = (BYTE*)MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize);
MapViewOfFileEx(hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize,
pBuf+bufferSize);
Oh hey, this is the topic which worried me a lot lately. I needed posix-optimised ring buffer on Windows, mostly because of its random-access interface, but never had any idea on how to implement it. Now, the code proposed by @1800 INFORMATION works sometimes, sometimes it doesn't, but the idea is great anyway.
The thing is, MapViewOfFileEx
sometimes fails with ERROR_INVALID_ADDRESS meaning that it cannot map the view to pBuf+bufferSize
. This is because the MapViewOfFile
called before selects a free address space of bufferSize
length (starting from pBuf
), but it doesn't garantee this address space to be bufferSize*2
long. And why would we need bufferSize*2
virtual memory? Because our ring buffer needs to wrap. This is what the second mapping view is for. When the read or write pointer leaves the first view, it enters the second view (because they are contigous in memory), but actually it starts over at the same mapping.
UINT_PTR addr;
HANDLE hMapFile;
LPVOID address, address2;
hMapFile = CreateFileMapping ( // create a mapping backed by a pagefile
INVALID_HANDLE_VALUE,
NULL,
PAGE_EXECUTE_READWRITE,
0,
bufferSize*2,
"Local\\mapping" );
if(hMapFile == NULL)
FAIL(CreateFileMapping);
address = MapViewOfFile ( // find a free bufferSize*2 address space
hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize*2 );
if(address==NULL)
FAIL(MapViewOfFile);
UnmapViewOfFile(address);
// found it. hopefully it'll remain free while we map to it
addr = ((UINT_PTR)address);
address = MapViewOfFileEx (
hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize,
(LPVOID)addr );
addr = ((UINT_PTR)address) + bufferSize;
address2 = MapViewOfFileEx (
hMapFile,
FILE_MAP_ALL_ACCESS,
0,
0,
bufferSize,
(LPVOID)addr);
if(address2==NULL)
FAIL(MapViewOfFileEx);
// when you're done with your ring buffer, call UnmapViewOfFile for
// address and address2 and CloseHandle(hMapFile)