Кольцевой буфер Windows без копирования - PullRequest
6 голосов
/ 19 июня 2009

В Запись в Википедии кольцевого буфера , есть пример кода , показывающий взлом для UNIX систем, в которых виртуальная память, прилегающая к фрагменту памяти, равна сопоставляется с той же физической памятью, реализуя кольцевой буфер без необходимости каких-либо memcpy и т. д. Мне было интересно, есть ли способ сделать что-то подобное в Windows ?

Спасибо, Фрейзер

Ответы [ 2 ]

10 голосов
/ 19 июня 2009

Я действительно не следовал всем деталям примера в Википедии. Имея это в виду, вы отображаете память в Windows, используя CreateFileMapping и MapViewOfFile , однако MapViewOfFile не позволяет указывать базовый адрес для сопоставления. MapViewOfFileEx может использоваться для указания базового адреса, поэтому, возможно, вы могли бы использовать аналогичную технику.

У меня нет никакого способа сказать, сработает ли это на самом деле:

// 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);
5 голосов
/ 19 ноября 2012

О, эй, эта тема меня очень беспокоила в последнее время. Мне нужен кольцевой буфер, оптимизированный для 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)
...