Windows环缓冲区无需复制

Rob*_*ser 6 c memory windows circular-buffer

Ring Buffer的维基百科条目中,有一个示例代码显示UNIX系统的hack,其中相邻虚拟内存到一块内存映射到相同的phbysical内存,从而实现一个环形缓冲区,而不需要任何memcpy等.我想知道如果在Windows中有类似的东西吗?

谢谢,弗雷泽

180*_*ION 10

我并没有真正遵循维基百科中的示例的所有细节.考虑到这一点,您使用CreateFileMappingMapViewOfFile在Windows中映射内存,但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);
Run Code Online (Sandbox Code Playgroud)

  • 离开这里吧 (4认同)

小智 5

哦,嘿,这是最近让我很担心的话题.我在Windows上需要posix优化的环形缓冲区,主要是因为它的随机访问接口,但从未对如何实现它有任何想法.现在,@ 1800 INFORMATION提出的代码有时会起作用,有时却不起作用,但无论如何这个想法都很棒.

问题是,MapViewOfFileExERROR_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)
Run Code Online (Sandbox Code Playgroud)

  • "它不保证这个地址空间是bufferSize*2 long" - 这可以通过使用`VirtualAlloc`和`MEM_RESERVE`标志来修复,然后两次调用`MapViewOfFileEx`,传递单个地址的两半范围由`VirtualAlloc`找到. (3认同)