Search code examples
c++boostmemory-mapped-filesboost-interprocessboost-circularbuffer

Using a circular buffer on disk


I was trying to create a memory-mapped circular buffer on disk using Boost, and I read this answer: https://stackoverflow.com/a/29265629/8474732

However, I have a hard time reading the circular buffer that was written. I tried to do a push_back on the "instance" variable, now the instance has size 1. Great. But how would I read the contents back? Or push_back additional elements at a later time? Creating another instance from the same allocator and mmf shows that the instance has size 0. I would want a function that can open a file on disk and push_back a value in the circular buffer, then return. I would want to call this function multiple times. An example of what I'm trying to do (derived from the linked answer):

#include <boost/circular_buffer.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>

namespace bip = boost::interprocess;

struct message {
    int data[32];
};

void writeFunction() {
    bip::managed_mapped_file mmf(bip::open_or_create, "./circ_buffer.bin", 4ul << 10);
    typedef bip::allocator<message, bip::managed_mapped_file::segment_manager> allocator;

    boost::circular_buffer<message, allocator> instance(10, mmf.get_segment_manager());

    struct message test;
    instance.push_back( test );
}

I would like to call this function when I want to write to the circular buffer on disk, and also be able to read it with another function (something like this):

void readFunction() {
    bip::managed_mapped_file mmf(bip::open_or_create, "./circ_buffer.bin", 4ul << 10);
    typedef bip::allocator<message, bip::managed_mapped_file::segment_manager> allocator;

    boost::circular_buffer<message, allocator> instance(10, mmf.get_segment_manager());

    for(struct message msg : instance) {
        cout << msg.string;
    }
}

Thanks for any help!


Solution

  • The linked post was a mimimal example that ONLY showed that the stateful allocator required for Boost Interprocess memory segments are supported in circular_buffer.

    To retrieve the circular buffer itself from the segment you need to construct the object itself in the shared memory segment (in addition to passing the shared-mem-allocator).

    DEMO

    No attention was payed to efficiency, this is just a dumb demo:

    Live On Coliru

    #include <boost/circular_buffer.hpp>
    #include <boost/interprocess/allocators/allocator.hpp>
    #include <boost/interprocess/managed_mapped_file.hpp>
    #include <iostream>
    
    namespace bip = boost::interprocess;
    
    struct message {
        int data[32];
    };
    
    void writeFunction() {
        bip::managed_mapped_file mmf(bip::open_or_create, "./circ_buffer.bin", 4ul << 10);
        typedef bip::allocator<message, bip::managed_mapped_file::segment_manager> allocator;
        typedef boost::circular_buffer<message, allocator> circ_buf;
    
        auto& instance = *mmf.find_or_construct<circ_buf>("named_buffer")(10, mmf.get_segment_manager());
    
        struct message test;
        instance.push_back( test );
        std::cout << "pushed a message (" << instance.size() << ")\n";
    }
    
    void readFunction() {
        bip::managed_mapped_file mmf(bip::open_or_create, "./circ_buffer.bin", 4ul << 10);
        typedef bip::allocator<message, bip::managed_mapped_file::segment_manager> allocator;
        typedef boost::circular_buffer<message, allocator> circ_buf;
    
        auto& instance = *mmf.find_or_construct<circ_buf>("named_buffer")(10, mmf.get_segment_manager());
    
        struct message test;
        while (!instance.empty()) {
            test = instance.front();
            instance.pop_front();
            std::cout << "popped a message (" << instance.size() << ")\n";
        }
    }
    
    int main() {
        writeFunction();
        writeFunction();
        writeFunction();
    
        readFunction();
    }
    

    Prints

    {"a":["1","2","3","4","5","6"]}
    4
    4
    No such node (b)
    element_at_checked