Map <int, void *> in shared memory using Boost :: interprocess
I am trying to build a map in the following type of shared memory
I create a shared memory region as follows:
managed_shared_memory segment(create_only ,"MyMap" ,size); ShMemAllocator_t alloc_inst (segment.get_segment_manager()); map = segment.construct<MyMap_t>("MyMap") (std::less<int>() ,alloc_inst); The values ββon the map are as follows:
typedef pair<MutexType, boost::interprocess::offset_ptr<void> > ValueType ; MutexType is the structure itself, which contains the read and write mutex (using read_lock and write_lock); defined as follows:
typedef struct mutex_struct{ sharable_lock<interprocess_mutex> read_lock(interprocess_mutex, defer_lock); scoped_lock<interprocess_mutex> write_lock(interprocess_mutex, defer_lock); } MutexType; "size" is the total size of the map (in terms of objects, so the sum of the data size that all void pointers point to).
How can I guarantee that this void * data is also in this memory segment that I created, how can I create it in an existing shared memory area). The reason for this is that I want to allocate this large buffer only once, but repeatedly removing / adding objects to it (the map simulates a cache). I have yet to find a way by which to allocate several objects in one memory segment inside the card. In addition, an attempt to highlight a MutexType pair returns a compilation error indicating that a βcallβ statement is not provided.
You are basically already there. Call any type of object that you allocate in SecondValue_t shared memory. Instead of ShMemAllocator_t define a different interprocess process allocator type, such as SecondValueAllocator_t , to highlight SecondValue_t objects. Whenever you want to insert a ValueType into the map, the second value of the ValueType is allocated by the SecondValueAllocator_t instance.
Here is a complete example, partially using the code in my answer for Interprocess Read / Write Lock with Boost :
#include <cstdlib> #include <functional> #include <iostream> #include <string> #include <utility> #include <boost/scope_exit.hpp> #include <boost/interprocess/managed_shared_memory.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/interprocess/allocators/private_node_allocator.hpp> #include <boost/interprocess/containers/map.hpp> #include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <boost/interprocess/sync/sharable_lock.hpp> #include <boost/interprocess/sync/upgradable_lock.hpp> #define SHARED_MEMORY_NAME "SO13783012-MyMap" // https://stackoverflow.com/questions/13783012/map-of-int-void-in-shared-memory-using-boostinterprocess using namespace boost::interprocess; typedef int SecondValue_t; typedef allocator<SecondValue_t, managed_shared_memory::segment_manager> SecondValueAllocator_t; typedef struct mutex_struct { //... } MutexType; typedef std::pair<MutexType, SecondValueAllocator_t::pointer> ValueType; typedef map<int, ValueType>::value_type MyMapValueType; typedef allocator<MyMapValueType, managed_shared_memory::segment_manager> MyMapEntryAllocator_t; typedef map<int, ValueType, std::less<int>, MyMapEntryAllocator_t> MyMap_t; struct shared_data { private: typedef boost::interprocess::interprocess_upgradable_mutex upgradable_mutex_type; mutable upgradable_mutex_type mutex; MyMap_t my_map; public: shared_data(const MyMapEntryAllocator_t& alloc) : my_map(MyMap_t::key_compare(), alloc) { } // Tries to get the mapped value for the given key `k'. If successful, the mapped value is // copied into `out' and `true' is returned. Otherwise, returns `false' and does not modify // `out'. bool try_get(MyMap_t::mapped_type& out, MyMap_t::key_type k) const { boost::interprocess::sharable_lock<upgradable_mutex_type> lock(mutex); MyMap_t::const_iterator pos = my_map.find(k); if (pos != my_map.end()) { out = pos->second; return true; } return false; } void put(MyMap_t::key_type k, MyMap_t::mapped_type v) { boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mutex); my_map.insert(MyMap_t::value_type(my_map.size(), v)); } }; int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " WHICH\n"; return EXIT_FAILURE; } const std::string which = argv[1]; if (which == "parent") { shared_memory_object::remove(SHARED_MEMORY_NAME); BOOST_SCOPE_EXIT(argc) { shared_memory_object::remove(SHARED_MEMORY_NAME); } BOOST_SCOPE_EXIT_END; managed_shared_memory shm(create_only, SHARED_MEMORY_NAME, 65536); MyMapEntryAllocator_t entry_alloc(shm.get_segment_manager()); shared_data& d = *shm.construct<shared_data>("theSharedData")(entry_alloc); SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); // Insert some test data. SecondValueAllocator_t::pointer p; p = second_value_alloc.allocate(1); second_value_alloc.construct(p, -3); d.put(0, std::make_pair(MutexType(), p)); p = second_value_alloc.allocate(1); second_value_alloc.construct(p, 70); d.put(1, std::make_pair(MutexType(), p)); p = second_value_alloc.allocate(1); second_value_alloc.construct(p, -18); d.put(2, std::make_pair(MutexType(), p)); p = second_value_alloc.allocate(1); second_value_alloc.construct(p, 44); d.put(3, std::make_pair(MutexType(), p)); p = second_value_alloc.allocate(1); second_value_alloc.construct(p, 0); d.put(4, std::make_pair(MutexType(), p)); // Go to sleep for a minute - gives us a chance to start a child process. sleep(60); } else { managed_shared_memory shm(open_only, SHARED_MEMORY_NAME); std::pair<shared_data *, std::size_t> find_res = shm.find<shared_data>("theSharedData"); if (!find_res.first) { std::cerr << "Failed to find `theSharedData'.\n"; return EXIT_FAILURE; } shared_data& d = *find_res.first; MyMap_t::mapped_type v; int i = 0; for (; d.try_get(v, i); ++i) { std::cout << i << ": " << *v.second << '\n'; } // Add an entry. srand(time(NULL)); SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); SecondValueAllocator_t::pointer p = second_value_alloc.allocate(1); second_value_alloc.construct(p, (rand() % 200) - 100); d.put(i, v = std::make_pair(MutexType(), p)); std::cout << "placed " << *v.second << " into the map.\n"; } return EXIT_SUCCESS; } Test it by first starting the parent process:
./SO13783012 parent
Then some children:
./SO13783012 child
Output Example:
> ./SO13783012 child 0: -3 1: 70 2: -18 3:44 4-0 placed 5: -63 into the map. > ./SO13783012 child 0: -3 1: 70 2: -18 3:44 4-0 5: -63 placed 6: -42 into the map. > ./SO13783012 child 0: -3 1: 70 2: -18 3:44 4-0 5: -63 6: -42 placed 7: -28 into the map.
You can use rearrangement in the distributor <>
// convert an allocator<T> to allocator<U> template<typename U> struct rebind { typedef Allocator<U> other; }; to do
typedef std::allocator< char, managed_shared_memory::segment_manager > char_alloc; then allocate your memory as follows
char_alloc char_alloc_obj; char * ptr = new (char_alloc_obj.allocate(size)) char[size]; void * vptr = (void *) ptr; By default, std :: allocator <> is smaller. The shared memory allocator will have state, so you need to figure out how to copy state between different types of allocators.