Как я могу вернуть непрозрачный дескриптор (void * или dword), который можно привести обратно к элементу значения, хранящемуся в карте boost :: interprocess?

Я немного сбит с толку семантикой «куча» и «значение по сравнению с ссылкой», вовлеченной в std::string ключ и большой struct значение в контейнер, как boost::interprocess::map,

Вот моя ситуация и некоторые typedefs, которые я использую:

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;

Вот как я вставляю AreaValueType (который является typedef для std :: pair):

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

Я полагаю, что приведенный выше код копирует A, который является std :: pair в моем локальном (не совместно используемой памяти) стеке, в область совместно используемой памяти. Могу ли я получить указатель на эту область разделяемой памяти внутри boost :: interprocess :: map или я ограничен извлечением этой записи целиком и сохранением ее целиком? (Другими словами, могу ли я сохранить что-то вроде структуры в карте межпроцессного ускорения и затем обновить один байт внутри этой записи, или мне нужно только обновить всю запись, заменив все байты в структуре DATA_AREA_DESC полностью новой байт.)

Некоторые дальнейшие разъяснения:

  1. У меня есть обычный старый API экспорта ANSI C DLL, который внутренне использует C ++ и Boost :: interprocess :: map. Ожидается, что функция создаст элемент на карте, а затем вернет дескриптор. Как я могу вставить что-то в boost :: interprocess :: map и затем вернуть дескриптор этой сущности пользователям, не являющимся C ++, предпочтительно приведение к void* или же unsigned long? Все, что я могу сделать — это извлечь данные из общей памяти, посмотрев значение ключа std :: string и записать новую запись в память. Вместо этого я хотел бы иметь возможность хранить ссылку на объект общей памяти.

  2. Если я не могу сделать это напрямую, как бы я сделал это косвенно? Я полагаю, что я мог бы сохранить std :: vector без общей памяти и выделить std :: string без общей памяти, содержащий значение areaKey, который является std :: string, а затем выполнить приведение void* пункт назад к std::string и затем используйте это, чтобы извлечь запись из области общей памяти. Все это выглядит как большая работа, чем это должно быть строго необходимо для чего-то столь элементарного. Может быть, boost :: interprocess :: map не подходит для моих требований?

Что я пробовал? Это компилируется, но я понятия не имею, правильно ли я делаю. Каким-то образом я чувствую себя ужасно внутри разыменования ::iterator вернулся из find, а затем сразу же взять его адрес так:

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

Обновить Выше работает. Однако очень разумный совет в ответе ниже НЕ работает. Использование boost :: interprocess :: string приводит к полному и полному отказу и сбоям во время выполнения. Использование std :: string, которое не имеет права работать, если только авторы Boost не закодировали поддержку std :: string в частности, на самом деле прекрасно работает.

7

Решение

Если handle должен быть указателем на std::pair в общей памяти, тогда ваш код будет работать предоставлена ты знаешь что areaKey находится на карте. В этом нет ничего плохого, за исключением того, что вам не нужно явное приведение (и если вы делаете приведение static_cast<void*>() будет предпочтительным).

Я не использовал boost::interprocess но я думаю, что вам нужно будет использовать boost::interprocess::string или std::basic_string с нестандартным распределителем для вашего ключа. Если не boost::interprocess делает что-то модное под капотом, используя std::string поместит указатель на локальную память (для строкового буфера) в разделяемую память, которая не будет иметь смысла в другом процессе.

Вот тестовая программа, которая использует карту со строковыми ключами:

#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;
}

Запустите его без аргументов, чтобы создать новый сегмент совместно используемой памяти, и, по крайней мере, с одним аргументом, чтобы открыть существующий сегмент совместно используемой памяти (вызов без аргументов уже должен выполняться). В обоих случаях программа будет итеративно читать ключ из stdinвставьте запись в карту и запишите stdout,

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]