2009-06-19 5 views
6
Kopieren

Auf Ring Buffer's Wikipedia entry, gibt es example code einen Hack für UNIX Systeme zeigen, wobei die benachbarten virtuellen Speicher auf einen Teil des Speichers mapped auf den gleichen phbysical Speicher sind, so dass ein Ringpuffer für jeden memcpy ohne die Notwendigkeit der Umsetzung, etc. Ich habe mich gefragt, ob es einen Weg zu etwas ähnlichem in Windows gibt?Windows-Ringpuffer ohne

Danke, Fraser

+0

Das Beispiel in Frage beseitigt nicht die Notwendigkeit für Memcpy beseitigen, ist es eine Notwendigkeit, eine DMA-Operation in zwei Fragmente zu tun, wenn der Betrieb über das Ende der Zuteilung für den Puffer Schritt würde. Es funktioniert nur im virtuellen Adressraum, da es darauf ankommt, einen seitengroßen Puffer anzuordnen, der auf zwei Plätze im virtuellen Speicher abgebildet wird. – RBerteig

+0

Errr ... ja, das. In meinem Fall übergebe ich den Zeiger an eine andere (Bibliotheks-) Funktion, die das Schreiben ausführt, so dass die Funktion einfach ihr eigenes Memcpy ausführen kann. –

Antwort

9

habe ich nicht wirklich alle Details des in wikipedia folgen. Vor diesem Hintergrund ordnen Sie Speicher in Windows unter Verwendung von CreateFileMapping und MapViewOfFile zu, MapViewOfFile ermöglicht es Ihnen jedoch nicht, eine Basisadresse für das Mapping anzugeben. MapViewOfFileEx kann verwendet werden, um eine Basisadresse anzugeben, vielleicht könnten Sie eine ähnliche Technik verwenden.

Ich habe keine Möglichkeit, wenn das funktionieren würde zu sagen, eigentlich:

// 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); 
+0

Arbeitete wie ein Charme; Vielen Dank! –

+4

Holen Sie die Hölle hier raus –

+1

Sorry meine erste Reaktion. Ich habe nicht wirklich erwartet, dass das funktioniert hätte –

5

Oh hey, das ist das Thema, das mir in letzter Zeit sehr viel besorgt. Ich benötigte einen posix-optimierten Ring-Buffer unter Windows, vor allem wegen seiner Random-Access-Schnittstelle, hatte aber nie eine Idee, wie man ihn implementiert. Jetzt funktioniert der von @ 1800 INFORMATION vorgeschlagene Code manchmal, manchmal nicht, aber die Idee ist trotzdem großartig.

Die Sache ist, MapViewOfFileEx schlägt manchmal mit ERROR_INVALID_ADDRESS was bedeutet, dass es die Ansicht nicht auf pBuf+bufferSize zuordnen kann. Dies liegt daran, dass die zuvor genannte MapViewOfFile einen freien Adressraum von bufferSize Länge (ab pBuf) auswählt, aber es garantiert nicht, dass dieser Adressraum bufferSize*2 lang ist. Und warum brauchen wir bufferSize*2 virtuellen Speicher? Weil unser Ringpuffer umbrechen muss. Dafür ist die zweite Mapping-Ansicht zuständig. Wenn der Lese- oder Schreibzeiger die erste Ansicht verlässt, tritt er in die zweite Ansicht ein (weil sie im Speicher zusammenhängend sind), aber tatsächlich beginnt er erneut bei der gleichen Zuordnung.

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) 
+3

"es garantiert nicht, dass dieser Adressraum pufferSize * 2 long" ist - dies kann behoben werden, indem 'VirtualAlloc' mit dem 'MEM_RESERVE'-Flag verwendet wird, dann zwei Aufrufe von' MapViewOfFileEx', wobei die beiden Hälften des Single übergeben werden Adressbereich von 'VirtualAlloc' gefunden. –