Windows -Ringpuffer ohne Kopieren
-
06-07-2019 - |
Frage
An Wikipedia -Eintrag von Ringpuffer, es gibt es Beispielcode einen Hack für zeigen Unix Systeme, bei denen der angrenzende virtuelle Speicher an ein Stück Speicher ist zugeordnet zum gleichen phbysikalischen Speicher, wodurch ein Ringpuffer implementiert wird, ohne dass es nach Bedarf erforderlich ist memcpy, usw. Ich habe mich gefragt, ob es einen Weg gibt, um so etwas Ähnliches in Fenster?
Danke, Fraser
Lösung
Ich habe nicht wirklich alle Details des Beispiels in Wikipedia gefolgt. In diesem Sinne kartieren Sie Speicher in Windows mit verwenden CreateFilemapping und MapViewoffile, Mit MapViewoffile können Sie jedoch nicht eine Basisadresse für die Zuordnung angeben. MapViewOfIFILEEx Kann verwendet werden, um eine Basisadresse anzugeben, sodass Sie möglicherweise eine ähnliche Technik verwenden können.
Ich habe keine Möglichkeit zu sagen, ob dies tatsächlich funktionieren würde:
// 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);
Andere Tipps
Oh hey, das ist das Thema, das mich in letzter Zeit sehr beunruhigt hat. Ich brauchte einen posix-optimierten Ringpuffer unter Windows, hauptsächlich wegen seiner zufälligen Zugriffsoberfläche, hatte aber nie eine Idee, wie sie es implementieren sollte. Jetzt funktioniert der von @1800 Informationen vorgeschlagene Code manchmal manchmal, manchmal nicht, aber die Idee ist ohnehin großartig.
Die Sache ist, MapViewOfFileEx
fällt manchmal mit error_invalid_address aus, was bedeutet, dass es die Ansicht nicht zuordnen kann pBuf+bufferSize
. Das liegt daran, dass die MapViewOfFile
Angerufen zuvor wählt ein kostenloser Adressraum von aus bufferSize
Länge (beginnend von pBuf
), aber es garantiert diesen Adressraum nicht zu sein bufferSize*2
lang. Und warum sollten wir brauchen bufferSize*2
virtueller Speicher? Weil unser Ringpuffer einwickeln muss. Dafür ist die zweite Mapping -Ansicht da. Wenn der Lese- oder Schreibzeiger die erste Ansicht verlässt, tritt er in die zweite Ansicht ein (weil er in Erinnerung anwesend ist), aber tatsächlich beginnt er bei derselben Zuordnung von vorhanden.
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)