6

Ring Buffer のウィキペディアのエントリには、メモリの一部に隣接する仮想メモリが同じ物理メモリにマップされ、 memcpyなどを必要とせずにリング バッファを実装するUNIXシステムのハックを示すサンプル コードがあります。 Windowsで似たような方法がある場合は?

ありがとう、フレイザー

4

2 に答える 2

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);
于 2009-06-19T08:53:50.863 に答える
5

ああ、これは最近私がとても心配しているトピックです。主にランダムアクセスインターフェイスのために、Windowsでposixに最適化されたリングバッファが必要でしたが、それを実装する方法についてはまったくわかりませんでした。現在、@ 1800 INFORMATIONによって提案されたコードは、機能する場合と機能しない場合がありますが、とにかくアイデアは素晴らしいです。

問題は、MapViewOfFileEx時々ERROR_INVALID_ADDRESSで失敗し、ビューをにマップできないことを意味しますpBuf+bufferSize。これは、 beforeが呼び出されたときに(から始まる)長さMapViewOfFileの空きアドレス・スペースが選択されるためですが、このアドレス・スペースが長くなることは保証されません。そして、なぜ仮想メモリが必要になるのでしょうか。リングバッファをラップする必要があるためです。これが、2番目のマッピングビューの目的です。読み取りまたは書き込みポインタが最初のビューを離れると、2番目のビューに入ります(メモリ内で隣接しているため)が、実際には同じマッピングからやり直します。bufferSizepBufbufferSize*2bufferSize*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)
于 2012-11-19T07:38:41.277 に答える