How can I return an opaque descriptor (void * or dword) that can be returned back to the value element stored in the boost :: interprocess map?

I am a little confused by the heap and by-value-vers-by-reference semantics associated with putting the std::string key and the large struct value in the container, for example boost::interprocess::map .

Here is my situation and some typedefs that I use:

 typedef std::string AreaKeyType; typedef DATA_AREA_DESC AreaMappedType; // DATA_AREA_DESC is a big struct. typedef std::pair<const AreaKeyType, AreaMappedType> AreaValueType; typedef boost::interprocess::allocator<AreaValueType, boost::interprocess::managed_shared_memory::segment_manager> AreaShmemAllocator; typedef boost::interprocess::map<AreaKeyType, AreaMappedType, std::less<AreaKeyType>, AreaShmemAllocator> AreaMap; 

This is how I insert an AreaValueType (which is a typedef for std :: pair):

  AreaValueType A(areaKey, arearec); anAreaMap->insert(A); 

I believe that the above code copies A, which is a std :: pair in my local (non-shared memory) stack, to the shared memory area. Can I get a handle to this shared memory area inside the boost :: interprocess :: card, or can you limit its selection and save it completely? (In other words, can I save something like a structure to the boost reprogramming card and then update one byte inside this record, or I just need to update the entire record, replacing all the bytes in the DATA_AREA_DESC structure, with a completely new byte.)

Some additional clarifications:

  • I have a plain old ANSI C DLL export api that internally uses C ++ and Boost :: interprocess :: map. The function is expected to create an element on the map and return a handle. How can I insert something into the boost :: interprocess :: map map and then return the handle to this object, other users other than C ++, it is preferable to discard on void* or unsigned long ? All I can do is extract material from shared memory by looking at the value of the std :: string key and write a new record to memory. I would like to save a reference to a shared memory object instead.

  • If I cannot do it directly, how would I do it indirectly? I suppose I could store std :: vector memory without memory and allocate std :: string non-shared memory by holding the areaKey value, which is std :: string, and then listing the void* element void* go back to std::string , and then use this to extract the record from the shared memory area. All this seems to be more work than should be strictly necessary for something so elementary. Maybe boost :: interprocess :: map is not suitable for my requirements?

What have i tried? This is what compiles, but I have no idea if I am doing this correctly. Somehow, I feel ugly at dereferencing the ::iterator returned from find , and then immediately taking its address like this:

 void ** handle; // actually a parameter in my api. *handle = (void*)&(*anAreaMap->find(areaKey)); 

Update the above work. However, very reasonable advice in the answer below DOES NOT work. Using boost :: interprocess :: string results in a complete and complete crash and crashes at runtime. Using std :: string, which does not have the right to work, unless the Boost authors encoded in std :: string especially work, actually work fine.

+7
source share
1 answer

If handle should be a pointer to std::pair in shared memory, then your code will work , you know that areaKey is on the map. There is nothing wrong with it, except that you do not need an explicit cast (and if you emphasize, then static_cast<void*>() will be preferred).

I did not use boost::interprocess , but I think you will need to use boost::interprocess::string or std::basic_string with a non-standard allocator for your key. If boost::interprocess does nothing under the hood, using std::string places a pointer to local memory (for string) in shared memory, which would not make sense in another process.

Here's a test program that uses a map with string keys:

 #include <iostream> #include <string> #include <boost/foreach.hpp> #include <boost/format.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <boost/interprocess/containers/map.hpp> #include <boost/interprocess/containers/string.hpp> #include <boost/interprocess/managed_shared_memory.hpp> namespace bi = boost::interprocess; #define SHARED_STRING 1 // set to 1 for interprocess::string, 0 for std::string static const char *SHARED_MEMORY_NAME = "MySharedMemory"; static const char *SHARED_MAP_NAME = "MySharedMap"; int main(int argc, char *argv[]) { #if SHARED_STRING typedef bi::allocator<char, bi::managed_shared_memory::segment_manager> CharAllocator; typedef bi::basic_string<char, std::char_traits<char>, CharAllocator> Key; #else typedef std::allocator<char> CharAllocator; typedef std::basic_string<char, std::char_traits<char>, CharAllocator> Key; #endif typedef int Mapped; typedef std::pair<const Key, Mapped> Value; typedef bi::allocator<Value, bi::managed_shared_memory::segment_manager> MapAllocator; typedef bi::map<Key, Mapped, std::less<Key>, MapAllocator> Map; bi::managed_shared_memory *segment; Map *map; if (argc <= 1) { // Create new shared memory segment. bi::shared_memory_object::remove(SHARED_MEMORY_NAME); segment = new bi::managed_shared_memory(bi::create_only, SHARED_MEMORY_NAME, 65536); MapAllocator mapAllocator(segment->get_segment_manager()); map = segment->construct<Map>(SHARED_MAP_NAME)(std::less<Key>(), mapAllocator); assert(map); } else { // Open existing shared memory segment. segment = new bi::managed_shared_memory(bi::open_only, SHARED_MEMORY_NAME); map = segment->find<Map>(SHARED_MAP_NAME).first; assert(map); } #if SHARED_STRING CharAllocator charAllocator(segment->get_segment_manager()); #else CharAllocator charAllocator; #endif while (true) { std::string input; if (!getline(std::cin, input)) break; map->insert(std::make_pair(Key(input.begin(), input.end(), charAllocator), 0)); BOOST_FOREACH(const Value& value, *map) std::cout << boost::format("('%s',%d)\n") % value.first % value.second; } delete segment; bi::shared_memory_object::remove(SHARED_MEMORY_NAME); return 0; } 

Run it without arguments to create a new shared memory segment and with at least one argument to open an existing shared memory segment (a call without arguments must already be running). In both cases, the program will iteratively read the key from stdin , insert a record on the card and write the contents to stdout .

+1
source

All Articles