1

I want to share vector of objects using boost interprocess. The objects are from the following structure:

struct Foo
    {
        int id;
        float time;
        bool isFoo;

        float myArray[7];

        std::vector<int> vectorData;
    };

I am creating boost inter process allocator and inter process vector:

typedef allocator<Foo, managed_shared_memory::segment_manager>  FooAllocator;

typedef std::vector<Foo, FooAllocator> FooVector;

In my main function i initialize the memory segment, the allocator and the vector, based on:

boost -> creating vectors in shared memory

so:

managed_shared_memory mem_segment(open_or_create, "MemShare", 65536);
const FooAllocator alloc_inst(mem_segment.get_segment_manager());

fooVector = mem_segment.find_or_construct<FooVector>("FooVector")(alloc_inst);

Now, this is working for every data type in the Foo structure except vector. So if i try to share this i get all the members from Foo, and for vector data i get "Undefined memory location" I know that std::vector can't be shared directly. So i created new Foo structure with boost::interprocess:vector

struct FooInter
    {
        int id;
        float time;
        bool isFoo;

        float myArray[7];
        MyVector* pointcloud;
    };

Where MyVector is:

typedef allocator<int, managed_shared_memory::segment_manager> VectorAllocator;
typedef boost::interprocess::vector<int, VectorAllocator> MyVector;

I am allocating memory for MyVector,

const VectorAllocator vec_alloc_inst(mem_segment.get_segment_manager());
MyVector* tmpVec = mem_segment.construct<MyVector>("MyVector")(vec_alloc_inst);

then what i try to do now is map the Foo to FooInter. I am mapping the vector data in for loop:

    for (int t = 0; t < foo.vectorData.size()-1; t++) {
        tmpVec->push_back(foo.vectorData[t]);
    }

And then copy the tmpVec into fooInter.vectorData:

memcpy(fooInter.pointcloud, tmpVec, sizeof(int) * tmpVec->size());

This works but not for the whole size of foo.vectorData. So it works for 100 items, but if i go with foo.vectorData.size() it returns bad memory alloc.

Can somebody help me with this. I need to know the proper way to share a structure of this type. I feel that what i am doing is entirely wrong. Maybe i need to serialize the vector into string or something similar.

Edit:

Based on the answer from sehe:

I have object msg from type:

struct Foo
    {
        int id;
        float time;
        bool isFoo;

        float myArray[7];

        std::vector<int> pointcloud;
    };

i need to pass that object in inter_foos. So in the code from sehe:

int main() {
    auto segment = Shared::open();
    auto& inter_foos = *segment.find_or_construct<InterFoos>("InterFoos")(segment.get_segment_manager());

    // you can directly append to the shared memory vector
    int nextid = inter_foos.size();
    //instead of this
    inter_foos.push_back({++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, Ints ({10,20,30}, segment.get_segment_manager()) });
    //i need this
        inter_foos.push_back({msg.id, msg.time, true, msg.myArray, Ints (msg.pointcloud, segment.get_segment_manager()) });

    //i can't pass msg.poincloud to this object!!!

    // or copy from a non-shared vector:
    std::vector<Foo> const local {
        {++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, {10,20,30} },
        {++nextid, 1, true, {.2,.3,.4,.5,.6,.7,.8}, {20,30,40} },
        {++nextid, 2, true, {.3,.4,.5,.6,.7,.8,.9}, {30,40,50} },
    };

    for (auto& local_foo : local)
        inter_foos.emplace_back(local_foo);

    // print the current contents
    for (auto& foo : inter_foos)
        std::cout << foo << "\n"; 
}
sehe
  • 374,641
  • 47
  • 450
  • 633
Dusko Murtovski
  • 138
  • 3
  • 15

2 Answers2

1

I cannot imagine that using memcpy to copy a MyVector is going to work well. Surely what you need is:

void FooInter::setVector(const std::vector<int>& vec) {
    const VectorAllocator vec_alloc_inst(mem_segment.get_segment_manager());
    const auto tmp = mem_segment.construct<MyVector>("MyVector")(vec_alloc_inst);
    tmp->insert(tmp->begin(), vec.begin(), vec.end());
    pointcloud = tmp;
}

In other words, construct the object pointed to by pointcloud, and then insert into it.

  • I get read access violation on insert, probably because pointcloud is not allocated hen we try to perform this operation – Dusko Murtovski Feb 14 '18 at 08:27
  • Don't say "I cannot imagine" if you really mean "Everybody should know that's illegal and leads to [Undefined Behaviour](https://en.wikipedia.org/wiki/Undefined_behavior)" – sehe Feb 14 '18 at 10:31
  • @DuskoMurtovski Sorry. That was a thinko on my part. Fixed to use tmp. – Martin Bonner supports Monica Feb 14 '18 at 11:37
  • @MartinBonner thanks, i get std:lenght_error in next_capacity.hpp. This is practically the same error what i get whet trying to copy the vector data using for loop. The length of vec is 3646400. Could this be the problem? – Dusko Murtovski Feb 14 '18 at 12:42
  • @sehe : "Everyone should know it's illegal" - a) only if they know its not POD; b) do we *really* need to write everything completely po-faced? – Martin Bonner supports Monica Feb 14 '18 at 16:52
  • Everybody should know vector isn't POD. (I'm not sure what po-faced means, but I think it's harmful to blur factual information under a guise of irony/sarcasm) – sehe Feb 14 '18 at 16:59
1

You can use the approach from

See this Demo¹

Live On Coliru

#include <boost/interprocess/managed_shared_memory.hpp>

#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/container/scoped_allocator.hpp>

#include <iostream>
#include <vector>

namespace Shared {
    namespace bip = boost::interprocess;
    namespace bc  = boost::container;

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

    Segment open() { return { bip::open_or_create, "MySharedMemory", 10ul<<20 }; }

    template <typename Alloc = Alloc<void> >
    struct Foo {
        using allocator_type = typename Alloc::template rebind<Foo>::other;
        using Ints = bip::vector<int, typename Alloc::template rebind<int>::other>;

        Foo(int id, float time, bool isFoo = false, std::initializer_list<float> floats = {}, Ints data = {})
            : id(id), time(time), isFoo(isFoo), vectorData(std::move(data))
        {
            std::copy_n(floats.begin(), std::min(floats.size(), 7ul), myArray);
        }

        template <typename OA, typename A>
        Foo(Foo<OA> const& other, A alloc = {}) 
            : id(other.id), time(other.time), isFoo(other.isFoo),
              vectorData(other.vectorData.begin(), other.vectorData.end(), alloc)
        {
            std::copy(std::begin(other.myArray), std::end(other.myArray), myArray);
        }

        int   id;
        float time;
        bool  isFoo;
        float myArray[7] = {};
        Ints  vectorData;
    };

    template <typename A>
    std::ostream& operator<<(std::ostream& os, Foo<A> const& f) {
        os << "{" 
           << f.id << ", "
           << std::fixed << f.time << ", "
           << std::boolalpha << f.isFoo << ", "
           << "[";

        std::copy(std::begin(f.myArray), std::end(f.myArray), std::ostream_iterator<float>(std::cout, ";"));
        os << "], [";
        std::copy(std::begin(f.vectorData), std::end(f.vectorData), std::ostream_iterator<int>(std::cout, ";"));
        return os << "] }";
    }

}

using Foo       = Shared::Foo<std::allocator<void> >;
using InterFoo  = Shared::Foo<>;

using InterFoos = Shared::Vector<InterFoo>;
using Ints      = Shared::Vector<int>;

int main() {
    auto segment = Shared::open();
    auto& inter_foos = *segment.find_or_construct<InterFoos>("InterFoos")(segment.get_segment_manager());

    // you can directly append to the shared memory vector
    int nextid = inter_foos.size();
    inter_foos.push_back({++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, Ints ({10,20,30}, segment.get_segment_manager()) });

    // or copy from a non-shared vector:
    std::vector<Foo> const local {
        {++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, {10,20,30} },
        {++nextid, 1, true, {.2,.3,.4,.5,.6,.7,.8}, {20,30,40} },
        {++nextid, 2, true, {.3,.4,.5,.6,.7,.8,.9}, {30,40,50} },
    };

    for (auto& local_foo : local)
        inter_foos.emplace_back(local_foo);

    // print the current contents
    for (auto& foo : inter_foos)
        std::cout << foo << "\n"; 
}

Prints:

{1, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{2, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{3, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
{4, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }

Second run:

{1, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{2, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{3, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
{4, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }
{5, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{6, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
{7, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
{8, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }

Scoped Allocators

Note that this:

    for (auto& local_foo : local)
        inter_foos.emplace_back(local_foo);

works because of scoped allocators being supported and passed along by Boost's container implementations. If you didn't use it, thing would look like this: Live On Coliru

template <typename T> using Alloc = bip::allocator<T, Manager>;
// ...

for (auto& local_foo : local)
    inter_foos.emplace_back(local_foo, segment.get_segment_manager());

¹ using mapped file because shared memory is not supported on COLIRU

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for the reply. I don't know how to initialize inter_foos with the values from fooInter.pointcloud. You are basically using initilaizer_list. So how do i use the vector instead of the constant list? – Dusko Murtovski Feb 15 '18 at 14:40
  • Can you show me exactly what you are stuck at now? In my approach, `pointcloud` is not a raw pointer member anymore (that's creating your problems, because you are having to do memory management manually then). [Hint: you can edit my live sample until it reflects your problem] – sehe Feb 15 '18 at 14:47
  • Instead of this: inter_foos.push_back({++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, Ints ({10,20,30}, segment.get_segment_manager()) }); i need to do this: inter_foos.push_back({msg.id, msg.time, msg.isKeyframe, msg.myArray, Ints (msg.pointcloud, segment.get_segment_manager()) }); where msg is object from: struct Foo { int id; float time; bool isFoo; float myArray[7]; std::vector pointcloud; }; can you see what i mean? How do i put pointcloud into inter_foos. I also had problems with myArray – Dusko Murtovski Feb 15 '18 at 14:52
  • Uhoh, comment threads are not going to work well in this fashion. Either post a sample on Coliru (or pastebin or whatever), edit your original question or consider posting a new question. – sehe Feb 15 '18 at 14:53
  • I edited my question, please check the comments in the code – Dusko Murtovski Feb 15 '18 at 15:02
  • Ok, so am I right in thinking that the only problem you face is that the original `Foo` cannot be altered? Because then it's just [one extra conversion constructor](http://coliru.stacked-crooked.com/a/b373e4cb3fe5f8ee), or perhaps even just making [the existing one more generic](http://coliru.stacked-crooked.com/a/d95fe028988e0343) – sehe Feb 15 '18 at 15:13
  • That was not my problem but while i was looking at that i understood how this works. So thanks, i will mark this as a solution. My problem was with the size of the vectorData which was more then 3 millions ints. I had to increase the size of shared memory block. – Dusko Murtovski Feb 16 '18 at 08:21