1. ホーム
  2. c++

[解決済み] CreateFileMapping、MapViewOfFile、ハンドルリーク c++

2022-02-08 20:32:05

質問

背景は? 複数のプロセスからアクセス可能なメモリマップドファイルを作成しようとしています。以下のコードでは、物事を簡単にするために、私が現在持っている質問に関連するコードのみを入れています。msdnによると、私はファイルマップを作成し、ファイルのビューをマップし、CreateFileMappingから受け取ったハンドルを閉じ、MapViewOfFileは私のFileMapを生かし続けることができるはずです。FileMapは、私がUnmapViewOfFileするまで、まだアクセス可能であるべきです。

MSDN CreateFileMapping機能

ファイルマッピングオブジェクトのマッピングされたビューは、オブジェクトへの内部参照を維持し、それへのすべての参照が解放されるまで、ファイルマッピングオブジェクトは閉じません。したがって、ファイルマッピングオブジェクトを完全にクローズするには、アプリケーションは UnmapViewOfFile を呼び出してファイルマッピングオブジェクトのすべてのマップされたビューをアンマップし、CloseHandle を呼び出してファイルマッピングオブジェクトハンドルをクローズする必要があります。これらの関数は、どのような順番でも呼び出すことができます。

問題あり。 ファイルのビューを正常にマッピングした後、CreateFileMapping によって受け取ったハンドルを閉じると、FileMap が存在しなくなり(まだ存在するはず)、MemMapFileReader はエラー 0 で新しいマップを作成できます(エラー 183 'already exists' を受け取るはずなのに...)。

悪い解決策 ハンドルを閉じないことで、MemMapFileReaderプログラムからアクセスできますが、プロセスが終了するまでハンドルが閉じられないため、MemMapFileCreatorでハンドルリークが発生します。

質問です。 何が足りないのか、何が間違っているのか?

MemMapFileCreator

#include "stdafx.h"


#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#define BUF_SIZE 256
TCHAR szName[] = TEXT("MyFileMappingObject");
TCHAR szMsg[] = TEXT("Message from first process.");

int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;

hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,    // use paging file
    NULL,                    // default security
    PAGE_READWRITE,          // read/write access
    0,                       // maximum object size (high-order DWORD)
    BUF_SIZE,                // maximum object size (low-order DWORD)
    szName);                 // name of mapping object

DWORD lastError = GetLastError();
if (hMapFile == NULL)
{
    _tprintf(TEXT("Could not create file mapping object (%d).\n"),
        GetLastError());
    std::cin.get();
    return 1;
}
pBuf = (LPTSTR)MapViewOfFile(hMapFile,   // handle to map object
    FILE_MAP_ALL_ACCESS, // read/write permission
    0,
    0,
    BUF_SIZE);

if (pBuf == NULL)
{
    _tprintf(TEXT("Could not map view of file (%d).\n"),
        GetLastError());

    CloseHandle(hMapFile);

    std::cin.get();
    return 1;
}


CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));

CloseHandle(hMapFile);

_getch();


UnmapViewOfFile(pBuf);
return 0;
}

MemMapFileReader

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <iostream>
#pragma comment(lib, "user32.lib")

#define BUF_SIZE 256
TCHAR szName[] = TEXT("MyFileMappingObject");

int _tmain()
{
HANDLE hMapFile;
LPCTSTR pBuf;

hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,
    NULL,
    PAGE_READWRITE,   // read/write access
    0,
    BUF_SIZE,
    szName);               // name of mapping object
DWORD lastError = GetLastError();
if (hMapFile == NULL)
{
    _tprintf(TEXT("Could not open file mapping object (%d).\n"),
        GetLastError());
    std::cin.get();
    return 1;
}

pBuf = (LPTSTR)MapViewOfFile(hMapFile, // handle to map object
    FILE_MAP_ALL_ACCESS,  // read/write permission
    0,
    0,
    BUF_SIZE);

if (pBuf == NULL)
{
    _tprintf(TEXT("Could not map view of file (%d).\n"),
        GetLastError());

    CloseHandle(hMapFile);

    std::cin.get();
    return 1;
}

MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);

UnmapViewOfFile(pBuf);

CloseHandle(hMapFile);

std::cin.get();
return 0;
}

解決方法は?

MSDNより。

<ブロッククオート

ファイル マッピング オブジェクトのマップされたビューは、オブジェクトへの内部参照を維持し、ファイル マッピング オブジェクトは、それへのすべての参照が解放されるまで閉じません。したがって、ファイル マッピング オブジェクトを完全にクローズするには、アプリケーションは UnmapViewOfFile を呼び出してファイル マッピング オブジェクトのすべてのマップされたビューをアンマップし、CloseHandle を呼び出してファイル マッピング オブジェクト ハンドルをクローズする必要があります。これらの関数は、どのような順番でも呼び出すことができます。

CreateFileMappingのドキュメントによると、ファイルを完全に閉じるにはすべてのハンドルを閉じる必要があり、順序は関係ないとのことです。このロジックは反転できません。あるハンドルを閉じると、ファイル マッピングが「閉じていない」かのように、他のハンドルを使用することはできません。

言い換えれば、ファイル・マッピングをクリーンアップするには、すべてのハンドルを任意の順序で閉じる必要があるということです。しかし、基礎となるファイルマッピングオブジェクトを閉じて、それに依存するビューをまだ使用することはできません。