2009-06-19 12 views
6

In Ring Buffer's Wikipedia entry, c'è example code mostra un hack per UNIX sistemi in cui la memoria virtuale adiacente ad una porzione della memoria è mapped sulla stessa memoria phbysical, attuando così un buffer circolare senza la necessità di qualsiasi memcpy, ecc Mi stavo chiedendo se c'è un modo per qualcosa di simile in Windows?buffer circolare di Windows senza copiare

Grazie, Fraser

+0

Nell'esempio in questione non elimina la necessità di memcpy, si elimina la necessità di eseguire un'operazione DMA in due frammenti quando l'operazione passo oltre la fine della dotazione per il buffer. Funzionerà solo nello spazio degli indirizzi virtuali poiché dipende dalla disposizione di un buffer di dimensioni di pagina mappato su due posizioni nella memoria virtuale. – RBerteig

+0

Errr ... sì, quello. Nel mio caso, sto passando il puntatore a un'altra funzione (libreria) che fa la scrittura, in modo che la funzione possa semplicemente fare la propria memcpy. –

risposta

9

non ho davvero seguire tutti i dettagli dell'esempio in Wikipedia. Con questo in mente, si mappa memoria in Windows utilizzando CreateFileMapping e MapViewOfFile, tuttavia MapViewOfFile non consente di specificare un indirizzo di base per la mappatura. MapViewOfFileEx può essere usato per specificare un indirizzo di base, quindi forse potresti usare una tecnica simile.

non ho alcun modo di sapere se questo sarebbe effettivamente lavorare:

// 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

ha funzionato come un fascino; Grazie! –

+4

Vai fuori di qui –

+1

Scusa la mia prima reazione. Non mi aspettavo davvero che avrebbe funzionato –

5

Oh, hey, questo è il tema che mi preoccupava molto ultimamente. Avevo bisogno di un ring buffer ottimizzato per posix su Windows, principalmente per la sua interfaccia ad accesso casuale, ma non avevo mai avuto alcuna idea su come implementarlo. Ora, il codice proposto da @ 1800 INFORMATION funziona a volte, a volte no, ma l'idea è comunque ottima.

La cosa è, MapViewOfFileEx a volte non riesce con ERROR_INVALID_ADDRESS che significa che non può mappare la vista a pBuf+bufferSize. Ciò è dovuto al fatto che il MapViewOfFile chiamato prima seleziona uno spazio di indirizzi libero della lunghezza bufferSize (a partire da pBuf), ma non garantisce che lo spazio degli indirizzi sia bufferSize*2 lungo. E perché avremmo bisogno della memoria virtuale bufferSize*2? Perché il nostro buffer ad anello deve essere avvolto. Questo è ciò per cui è la seconda vista mappatura. Quando il puntatore di lettura o scrittura lascia la prima vista, entra nella seconda vista (perché sono contigui in memoria), ma in realtà ricomincia dalla stessa mappatura.

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

"non garantisce che questo spazio indirizzo sia bufferSize * 2 lungo" - questo può essere corretto usando 'VirtualAlloc' con il flag' MEM_RESERVE', quindi due chiamate a 'MapViewOfFileEx', passando le due metà del singolo intervallo di indirizzi trovato da 'VirtualAlloc'. –