1

I am trying to create a POD struct type and keep a vector of that struct in boost interprocess shared memory. What I have been doing and it's been working:

template <typename T>
    using Alloc = ipc::allocator<T, ipc::managed_shared_memory::segment_manager>;
using String = ipc::basic_string<char, std::char_traits<char>, Alloc<char>>;

struct SharedData
{
    template <typename Alloc>
    SharedData(size_t aSize, std::string_view aStr, Alloc alloc) : sz(aSize), data(aStr, alloc) {}

    size_t  sz;
    String  data;
};

I go ahead and create a vector of this struct which is cool and works, but I wanted to get cache locality when accessing i'th index of the vector. For that I wanted to get, data to be present in the same contiguous storage of the vector, so I changed the struct to:

struct SharedData
{           
    SharedData(size_t aSize) : sz(aSize) {}
    size_t  sz;
    char data[MAX_DATA_SIZE];
};

But this does not get allocated in the vector, when I create it using:

auto shared_vec = segment_.construct<Vector<SharedData>>((const char *) shared_vec_name.c_str())(segment_.get_segment_manager());
for (int i = 0; i < vector_size; i++)
    (*shared_vec).emplace_back(max_data_size);

It throws:

terminate called after throwing an instance of 'boost::interprocess::bad_alloc'
  what():  boost::interprocess::bad_alloc

Any idea what am I doing wrong here? I want to allocate a vector of POD type with cache locality as well, since String will have further dynamic allocations which is not desirable for my use case.

Akash
  • 939
  • 1
  • 8
  • 27

1 Answers1

0

char data[MAX_DATA_SIZE]; makes sizeof(SharedData) much larger. Depending on allocation pattterns the vector might reserve or reallocate running out of space in your segment.

Note that many string implementations have SSO, which means you may already have cache locality.

If you're really striving for POD data and complete cache control, I'd suggest switching to something like

 std::array<SharedData, N> instead_of_vector;

for some fixed capacity N. In that case you wouldn't need a managed segment, so consider using boost::interprocess::mappped_region directly instead of managed_shared_memory.

Note that there are many ways in between as well. Thinking of boost::static_vector or boost::small_vector. Also, consider that **simply doing a .reserve() up-front may solve your problems:

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    Thanks for the insight. I love the boost::interprocess::managed_shared_memory, how it ties shared memory usage with being pragmatic. I will stick to its usage for now. Also, I think emplacing step by step needs more memory than directly reserving objects at a go! And it actually helped. I switched to .reserve / .resize and it works perfectly. – Akash Nov 04 '22 at 05:30