How to prevent flushing to disk of a memory map opened on a windows temporary delete-on-close file

前端 未结 2 1964
夕颜
夕颜 2021-02-19 02:43

UPDATE 2 / TL;DR

Is there some way to prevent dirty pages from a windows temporary delete-on-close file being flushed as a result of cl

2条回答
  •  误落风尘
    2021-02-19 03:05

    After the bounty period expired without any answers that provided more insight or solved the mentioned problem, I decided to dig a little deeper and experiment some more with several combinations and sequences of operations.

    As a result, I believe I have found a way to achieve memory maps shared between processes over temporary, delete-on-close files, that are not being flushed to disk when they are closed.

    The basic idea involves creating the memory map when a temp file is newly created with a map name that can be used in a call to OpenFileMapping:

    // build a unique map name from the file name.
    auto map_name = make_map_name(file_name); 
    
    // Open or create the mapped file.
    auto mh = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, map_name.c_str());
    if (mh == 0 || mh == INVALID_HANDLE_VALUE) {
        // existing map could not be opened, create the file.
        auto fh = ::CreateFileA(name.c_str(), kReadWrite, kFileSharing, nullptr, CREATE_NEW, kTempFlags, 0);
        if (fh != INVALID_HANDLE_VALUE) {
            // set its size.
            LARGE_INTEGER newpos;
            newpos.QuadPart = desired_size;
            ::SetFilePointerEx(fh, newpos, 0, FILE_BEGIN);
            ::SetEndOfFile(fh);
            // create the map
            mh = ::CreateFileMappingA(mh, nullptr, PAGE_READWRITE, 0, 0, map_name.c_str());
            // close the file handle
            // from now on there will be no accesses using file handles.
            ::CloseHandle(fh);
        }
    }
    

    Thus, the file handle is only used when the file is newly created, and closed immediately after the map is created, while the map handle itself remains open, to allow opening the mapping without requiring access to a file handle. Note that a race condition exists here, that we would need to deal with in any "real code" (as well as adding decent error checking and handling).

    So if we got a valid map handle, we can create the view:

    auto map_ptr = MapViewOfFile(mh, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    if (map_ptr) {
        // determine its size.
        MEMORY_BASIC_INFORMATION mbi;
        if (::VirtualQuery(map_ptr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) > 0) 
            map_size = mbi.RegionSize;
    }
    

    When, some time later closing a mapped file: close the map handle before unmapping the view:

    if (mh == 0 || mh == INVALID_HANDLE_VALUE) {
        ::CloseHandle(mh);
        mh = INVALID_HANDLE_VALUE;
    }
    if (map_ptr) {
        ::UnmapViewOfFile(map_ptr);
        map_ptr = 0;
        map_size = 0;
    }
    

    And, according to the test I have performed so far, this does not cause flushing dirty pages to disk on close, problem solved. Well partially anyway, there may still be a cross-session map name sharing issue.

提交回复
热议问题