I am new to Boost. I have the following structure and want to store it in shared memory using Boost.
struct InData{
int x,y,h,w;
char* lbl;
};
In-turn this structure will be stored in Vector. Most of example talk about int or string datatype for Vectors. I would like if anbody can provide an example how to store user defined data type into boost shared memory.
You can easily store UDT in there, Boost's interprocess allocator will do the magic for you. However, storing raw-pointers is not gonna work.
So, let's start off with a sample without raw pointers:
struct InData {
int x = 0, y = 0, h = 0, w = 0;
shared_string label;
};
Assuming shared_string
is already define like e.g.
using shared_string = bip::basic_string<char, std::char_traits<char>, bip::allocator<char, SegmentManager>>;
I like to separate my datastructures from the choice of allocator, so I might write it more generically:
template <typename Alloc = std::allocator<char> >
struct BasicInData {
BasicInData(Alloc alloc = {}) : label(alloc) { }
int x = 0, y = 0, h = 0, w = 0;
string label;
};
Now, you can "freely" add this to a shared memory/memory mapped segment. I usually set up some typedefs in a namespace:
using InData = BasicInData<>; // just heap allocated
namespace Shared {
using segment = bip::managed_mapped_file; // or managed_shared_memory
using segment_manager = segment::segment_manager;
template <typename T> using alloc = bip::allocator<T, segment_manager>;
template <typename T> using vector = bip::vector<T, alloc<T> >;
using InData = BasicInData<alloc<char> >; // shared memory version
}
Now you can use the vector<InData>
from Shared
in a managed memory segment:
segment smt(bip::open_or_create, "data.bin", 10u<<20); // 10 MiB
vector<InData>* v = smt.find_or_construct<vector<InData> >("InDataVector")(smt.get_segment_manager());
This creates a vector inside a file of 10 MiB.
I've extended the demo with some functions to generate random data. The program looks like:
int main() {
Shared::segment smt(bip::open_or_create, "data.bin", 10u<<20); // 10 MiB
auto& data = Shared::locate(smt);
std::generate_n(std::back_inserter(data), 2, [&smt] { return generate(smt.get_segment_manager()); });
for(auto& d : data) {
std::cout << d << "\n";
}
}
Each time it's run it will add two randomly generated InData
structures. First time output could be e.g.
InData { 99, 7, 71, 65, nwlsovjiwv }
InData { 16, 51, 33, 34, nuujiblavs }
Then, second time will show the existing records plus two newly generated lines:
InData { 99, 7, 71, 65, nwlsovjiwv }
InData { 16, 51, 33, 34, nuujiblavs }
InData { 49, 26, 81, 30, snhcvholti }
InData { 48, 66, 19, 8, xtididuegs }
Live On Coliru
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp> // use for Coliru
#include <boost/interprocess/containers/vector.hpp> // boost/containers/vector.hpp
#include <boost/interprocess/containers/string.hpp> // boost/containers/string.hpp
#include <iostream>
#include <random>
namespace bip = boost::interprocess;
template <typename Alloc = std::allocator<char> >
struct BasicInData {
using string = bip::basic_string<char, std::char_traits<char>, typename Alloc::template rebind<char>::other>;
BasicInData(Alloc alloc = {}) :
label(alloc)
{ }
template <typename T>
BasicInData(int x, int y, int h, int w, T&& label, Alloc alloc = {}) :
x(x), y(y), h(h), w(w), label(std::forward<T>(label), alloc)
{ }
int x = 0, y = 0, h = 0, w = 0;
string label;
};
using InData = BasicInData<>; // just heap allocated
namespace Shared {
using segment = bip::managed_mapped_file; // or managed_shared_memory
using segment_manager = segment::segment_manager;
template <typename T> using alloc = bip::allocator<T, segment_manager>;
template <typename T> using vector = bip::vector<T, alloc<T> >;
using InData = BasicInData<alloc<char> >; // shared memory version
vector<InData>& locate(segment& smt) {
auto* v = smt.find_or_construct<vector<InData> >("InDataVector")(smt.get_segment_manager());
assert(v);
return *v;
}
}
static std::mt19937 prng { std::random_device{} () };
// ugly quick and dirty data generator
template <typename SegmentManager>
Shared::InData generate(SegmentManager const& sm) {
static std::uniform_int_distribution<int> coord_dist(1,100);
static std::uniform_int_distribution<char> char_dist('a', 'z');
char buf[11] = { 0 };
auto rand_coord = [] { return coord_dist(prng); };
auto gen_ch = [] { return char_dist(prng); };
auto rand_label = [&] { std::generate(std::begin(buf), std::end(buf)-1, gen_ch); return buf; };
return { rand_coord(), rand_coord(), rand_coord(), rand_coord(), rand_label(), sm };
}
// demo:
template <typename Alloc>
static std::ostream& operator<<(std::ostream& os, BasicInData<Alloc> const& d) {
return os << "InData { " << d.x << ", " << d.y << ", " <<
d.w << ", " << d.h << ", " << d.label << " }";
}
int main() {
Shared::segment smt(bip::open_or_create, "data.bin", 10u<<10); // 10 Kb for coliru
auto& data = Shared::locate(smt);
std::generate_n(std::back_inserter(data), 2, [&smt] { return generate(smt.get_segment_manager()); });
for(auto& d : data) {
std::cout << d << "\n";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With