2009-06-19 10 views
6

En Ring Buffer's Wikipedia entry, hay example code mostrando un corte para UNIX regímenes en los que la memoria virtual junto a un trozo de la memoria es mapped a la misma memoria phbysical, implementando así una memoria cíclica sin la necesidad de ningún memcpy, etc. . Me preguntaba si hay alguna manera de algo similar en Windows?memoria cíclica de Windows sin copiar

Gracias, Fraser

+0

el ejemplo en cuestión no elimina la necesidad de establecimiento de memoria, que elimina la necesidad de realizar una operación de DMA en dos fragmentos cuando la operación daría un paso más allá del final de la asignación de la memoria intermedia. Solo funcionará en el espacio de direcciones virtuales, ya que depende de la organización de un búfer de tamaño de página que se asigna a dos lugares en la memoria virtual. – RBerteig

+0

Errr ... sí, eso. En mi caso, estoy pasando el puntero a otra función (biblioteca) que hace la escritura, por lo que la función puede hacer su propia memcpy. –

Respuesta

9

que en realidad no seguir todos los detalles del ejemplo en Wikipedia. Con esto en mente, mapea la memoria en Windows usando CreateFileMapping y MapViewOfFile, sin embargo MapViewOfFile no le permite especificar una dirección base para la asignación. MapViewOfFileEx se puede utilizar para especificar una dirección base por lo que tal vez podría utilizar una técnica similar.

que no tienen ninguna manera de saber si esto realmente funciona:

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

Funcionó como un encanto; ¡Gracias! –

+4

Lárgate de aquí –

+1

Disculpa mi reacción inicial. Realmente no esperaba que hubiera funcionado –

5

Oh hey, este es el tema que me preocupó mucho últimamente. Necesitaba un buffer de anillo posix optimizado en Windows, principalmente debido a su interfaz de acceso aleatorio, pero nunca tuve idea de cómo implementarlo. Ahora, el código propuesto por @ 1800 INFORMATION funciona a veces, a veces no, pero la idea es genial de todos modos.

El problema es que MapViewOfFileEx a veces falla con ERROR_INVALID_ADDRESS lo que significa que no puede asignar la vista a pBuf+bufferSize. Esto se debe a que el MapViewOfFile llamado anteriormente selecciona un espacio libre de direcciones de bufferSize de longitud (comenzando desde pBuf), pero no garantiza que este espacio de direcciones sea bufferSize*2 de largo. ¿Y por qué necesitaríamos la memoria virtual bufferSize*2? Porque nuestro buffer de anillo necesita envolverse. Esto es para lo que es la segunda vista de mapeo. Cuando el puntero de lectura o escritura sale de la primera vista, ingresa a la segunda vista (porque están contiguos en la memoria), pero en realidad comienza de nuevo en la misma asignación.

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

"no garantiza que este espacio de direcciones sea bufferSize * 2 long" - esto se puede solucionar usando 'VirtualAlloc' con el indicador' MEM_RESERVE', luego dos llamadas a 'MapViewOfFileEx', pasando las dos mitades del single rango de direcciones encontrado por 'VirtualAlloc'. –

Cuestiones relacionadas