Search code examples
c++visual-studio-2010boostmemory-mapped-files

Memory mapped file problems


In my c++ code I need to write a lot of data into a file and I would like to use the boost mapped file instead of using normal file. Only when I finish writing all the data in memory I would like to dump the mapped file to the disk on one shot.

I use Visual Studio 2010 on Windows Server 2008 R2 and boost 1.58.

I've never used mapped file so I tried to compile the example on the boost documentation

#include <iostream>
#include <fstream>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>


int main(int argc, char** argv) 
{
    using namespace boost::interprocess;

const char* fileName = "C:\\logAcq\\test.bin";
const std::size_t fileSize = 10000;

std::cout << "create file" << std::endl;

try
{
    file_mapping::remove(fileName);
    std::filebuf fbuf;
    fbuf.open(fileName, std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);

    std::cout << "set size" << std::endl;
    fbuf.pubseekoff(fileSize-1, std::ios_base::beg);
    fbuf.sputc(0);

    std::cout << "remove on exit" << std::endl;
    struct file_remove
    {
        file_remove(const char* fileName)
            :fileName_(fileName) {}
        ~file_remove(){ file_mapping::remove(fileName_); }
        const char *fileName_;
    }remover(fileName);

    std::cout << "create file mapping" << std::endl;
    file_mapping m_file(fileName, read_write);

    std::cout << "map the whole file" << std::endl;
    mapped_region region(m_file, read_write);

    std::cout << "get the address" << std::endl;
    void* addr = region.get_address();
    std::size_t size = region.get_size();

    std::cout << "write all memory to 1" << std::endl;
    memset(addr, 1, size);
}
catch (interprocess_exception &ex) 
{
    fprintf(stderr, "Exception %s\n", ex.what());
    fflush(stderr);
    system("PAUSE");

    return 0;
}

system("PAUSE");

return 0;
}

but I get the exception

Exception The volume for a file has been externally altered so that the opened file is no longer valid.

when I create the region

"mapped_region region(m_file, read_write)"

Any help is appreciate.

Thanks


Solution

  • Exception The volume for a file has been externally altered so that the opened file is no longer valid.

    Strongly suggests that the file is changed by another program, while it was mapped. And the error message indicates the change happened to affect the size in such a way that is not allowed.

    Avoid other programs writing to the file, or have proper synchronization and sharing precautions (like, don't change the size, or only grow etc.)

    UPDATE

    Your added SSCCE confirms that you held the file open while mapping:

    You need to close the fbuf before mapping the file. Also, you need to remove the mapping before allowing it to be removed.

    Working sample:

    Live On Coliru

    #include <iostream>
    #include <fstream>
    #include <boost/interprocess/file_mapping.hpp>
    #include <boost/interprocess/mapped_region.hpp>
    
    int main() {
        using namespace boost::interprocess;
    
        const char *fileName = "test.bin";
        const std::size_t fileSize = 10000;
    
        std::cout << "create file " << fileName << std::endl;
    
        try {
            file_mapping::remove(fileName);
            {
                std::filebuf fbuf;
                fbuf.open(fileName, std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
    
                std::cout << "set size" << std::endl;
                fbuf.pubseekoff(fileSize - 1, std::ios_base::beg);
                fbuf.sputc(0);
            }
    
            std::cout << "remove on exit" << std::endl;
            struct file_remove {
                file_remove(const char *fileName) : fileName_(fileName) {}
                ~file_remove() { file_mapping::remove(fileName_); }
                const char *fileName_;
            } remover(fileName);
    
            {
                std::cout << "create file mapping" << std::endl;
                file_mapping m_file(fileName, read_write);
    
                std::cout << "map the whole file" << std::endl;
                mapped_region region(m_file, read_write);
    
                std::cout << "get the address" << std::endl;
                void *addr = region.get_address();
                std::size_t size = region.get_size();
    
                std::cout << "write all memory to 1" << std::endl;
                memset(addr, 1, size);
            }
        } catch (interprocess_exception &ex) {
            fprintf(stderr, "Exception %s\n", ex.what());
            fflush(stderr);
        }
    }