О, эй, эта тема меня очень беспокоила в последнее время. Мне нужен кольцевой буфер, оптимизированный для posix, в Windows, в основном из-за его интерфейса с произвольным доступом, но я никогда не представлял, как его реализовать. Теперь код, предложенный @ 1800 INFORMATION, иногда работает, иногда нет, но идея в любом случае великолепна.
Дело в том, что MapViewOfFileEx
иногда завершается ошибкой с ERROR_INVALID_ADDRESS, что означает, что он не может сопоставить представление с pBuf+bufferSize
. Это связано с тем, что вызываемый ранее MapViewOfFile
выбирает свободное адресное пространство длиной bufferSize
(начиная с pBuf
), но не гарантирует, что это адресное пространство будет иметь длину bufferSize*2
. И зачем нам нужна bufferSize*2
виртуальная память? Потому что наш кольцевой буфер нужно обернуть. Это то, для чего предназначен второй вид отображения. Когда указатель чтения или записи покидает первое представление, он входит во второе представление (поскольку они являются непрерывными в памяти), но фактически он начинается заново при том же отображении.
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)