2

I am trying to use boost::interprocess to allocate a very simple data structure in shared memory but I cannot quite figure out how to use the boost interprocess allocators to perform the memory allocations/deallocations within the shared memory segment which I allocate as follows

using namespace boost::interprocess;
shared_memory_object::remove("MySharedMem");
mSharedMemory = std::make_unique<managed_shared_memory>(
    open_or_create, "MySharedMem", 65536);

I previously asked a similar question but unfortunately I never got any answers. MyStruct below is essentially an array with a length field indicating the size of the array. For now I have a simple length field but I will add some other constructor arguments later (bool's and other simple types).

In order to allocate this in the shared memory segment, I know I have to do something with allocators but I cannot find a similar example where I have a user defined type containing an array/pointer field.

    using MyType = struct MyType {
        explicit MyType(const size_t aSize)
            : mSize(aSize)
            , mpData(new char[aSize])
        {}

        ~MyType() {
            delete[]mpData;
        }
        size_t mSize;
        char * mpData;
    };

    using MyTypeAllocator = boost::interprocess::allocator<MyType,
        boost::interprocess::managed_shared_memory::segment_manager>;

    // Initialize the shared memory STL-compatible allocator
    MyTypeAllocator alloc(mSharedMemory->get_segment_manager());
T.C.
  • 133,968
  • 17
  • 288
  • 421
johnco3
  • 2,401
  • 4
  • 35
  • 67
  • You need to teach `MyType` to also use an allocator rather than use `operator new`. – T.C. Oct 24 '17 at 17:44
  • @T.C. Thanks, any pointers on how I might do that? I've been searching for some simple example. Its very easy with ints or uint32_t's as they are trivial, the problem with a struct with a pointer field is that the sizeof() is funny as it does not account for the size of the allocated bytes that also need to be stored. I think this has something to do with nodes in the boost::interprocess world but I am pretty new to this. – johnco3 Oct 24 '17 at 17:52

1 Answers1

1

Just don't do manual allocation. If you want a contiguous allocation of aSize elements of type char, that's what C++ has std::vector for.

Best of all, std::vector already knows how to use another allocator, so there is really no reason not to use it:

template <typename Alloc>
struct MyType {
    explicit MyType(size_t aSize, Alloc alloc = {}) : mData(aSize, alloc) {}

  private:
    std::vector<char, Alloc> mData;
};

Now to play well with standard library construct/scoped allocators, you might want to define the allocator_type nested type:

    using allocator_type = Alloc; // typename Alloc::template rebind<char>::other;

That's all. Just use it as any standard library type that has an allocator:

int main() {
    using namespace Shared;

    Shared::remove("MySharedMem");
    auto memory = Segment(create_only, "MySharedMem", 65536);

    using A = Alloc<char>;
    A alloc(memory.get_segment_manager());

    auto* data = memory.find_or_construct<MyType<A>>("data")(1024, memory.get_segment_manager());

    return data? 0 : 255;
}

I created a few convenience typedefs in the Shared namespace, for maintainability. Here's the full sample

Full Sample

Live On Coliru ¹

#include <boost/interprocess/managed_shared_memory.hpp>
#include <vector>

template <typename Alloc>
struct MyType {
    using allocator_type = typename Alloc::template rebind<char>::other;

    explicit MyType(size_t aSize, Alloc alloc = {}) : mData(aSize, alloc) {}

  private:
    std::vector<char, Alloc> mData;
};

namespace Shared {
    namespace bip = boost::interprocess;

    using Segment = bip::managed_shared_memory;
    using Manager = Segment::segment_manager;
    template <typename T> 
        using Alloc = bip::allocator<T, Manager>;

    void remove(char const* name) { bip::shared_memory_object::remove(name); }

    using bip::create_only;
}

int main() {
    using namespace Shared;

    Shared::remove("MySharedMem");
    auto memory = Segment(create_only, "MySharedMem", 65536);

    using A = Alloc<char>;
    A alloc(memory.get_segment_manager());

    auto* data = memory.find_or_construct<MyType<A>>("data")(1024, memory.get_segment_manager());

    return data? 0 : 255;
}

¹ For Coliru uses managed mapped file because shared memory is not supported there

sehe
  • 374,641
  • 47
  • 450
  • 633
  • great answer as always, but would it be possible to add some additional simple members to MyType and have them stored in shared memory also, e.g. MyType taking a bool, uint64_t and possibly a string in addition to the aSize parameter. These first two extra parameters have trivial allocators and there are good examples on shm_string types with custom allocators, I’m not sure how the MyType would be correctly saved and subsequently restored from shared memory. – johnco3 Oct 25 '17 at 07:59
  • Of course. POD data is never an issue in [shared] memory – sehe Oct 25 '17 at 08:00
  • there is a lot going on under the covers of your example program, I am trying to understand it first: "using allocator_type = typename Alloc::template rebind::other" is very confusing and doesn't seem necessary (I think rebind has something to do with node allocations within a container, I commented out the line of code in VS and it still worked), Also, using A = Alloc - what is the parameter used for? It seems that this expands to boost::interprocess::allocator. – johnco3 Oct 25 '17 at 15:56
  • Then we construct alloc with 'memory.get_segment_manager()' - which I thought should be an 'int' argument, however get_segment_manager() returns a 'segment_manager *' which is not exactly an int. – johnco3 Oct 25 '17 at 15:56
  • About the nested typedef, I specifically said what I added it for. Feel free to disregard. – sehe Oct 25 '17 at 15:57
  • The int was a bit of leftover, I though I had removed that. – sehe Oct 25 '17 at 15:58
  • apologies for the nested typedef - my bad! You were clear – johnco3 Oct 25 '17 at 15:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157499/discussion-between-sehe-and-johnco3). – sehe Oct 25 '17 at 15:59