Карты карт размещены в общей памяти

Внутри boost::interprocess::managed_shared_memoryЯ пытаюсь создать boost::unordered_map внутри другого boost::unordered_map как значение, имеющее ключ как std::string для обеих карт. Эта карта в карте внутри сегмента общей памяти получает доступ к двум различным процессам, извлекающим значения из обоих внешних & внутренние карты.

Ниже моя реализация & Хотите знать, если это возможно / правильный путь или любой другой лучший способ возможен?

boost::interprocess::managed_shared_memory segment(boost::interprocess::open_or_create, "BOOST_SHM", 65536);

typedef std::string   KeyType;
typedef std::string   ValueType;
typedef std::pair<const KeyType, ValueType> MapType;
typedef boost::interprocess::allocator<MapType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::unordered_map<KeyType, ValueType, boost::hash<KeyType>, std::equal_to<KeyType>, ShmemAllocator> InMap;
ShmemAllocator alloc_inst(segment.get_segment_manager());
InMap *inside_map = segment.construct<InMap>("SHM_IN_MAP")(3, boost::hash<KeyType>(), std::equal_to<KeyType>(), alloc_inst);typedef std::pair<const KeyType, MapType> MIMType;
typedef boost::interprocess::allocator<MIMType, boost::interprocess::managed_shared_memory::segment_manager> MIMShmemAllocator;
typedef boost::unordered_map<KeyType, MapType, boost::hash<KeyType>, std::equal_to<KeyType>, MIMShmemAllocator> OutMap;
//MIMShmemAllocator alloc_inst(segment.get_segment_manager());   /*Commented due to Error*/
OutMap *outside_map = segment.construct<OutMap>("SHM_OUT_MAP")(3, boost::hash<KeyType>(), std::equal_to<KeyType>(), alloc_inst);

Другие детали:

gcc версия 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) на CentOS 7,
BOOST_LIB_VERSION «1_58»

3

Решение

Хорошо.

Так что было несколько основных ошибок и, возможно, некоторая путаница.

Далее, есть несколько хитростей, которые делают использование вложенных контейнеров с настраиваемыми (с сохранением состояния) распределителями гораздо более удобным.

Вот скопление всех трех подсказок в рабочем образце, которое, надеюсь, поможет!


  1. Ваши строки должен используйте распределители общей памяти

    В противном случае данные будут незаконно использовать в другом процессе. Использование строк приведет к Неопределенное поведение.

    По крайней мере, заставьте ваши строки использовать распределитель общей памяти:

    namespace Shared {
    using Segment   = bip::managed_shared_memory;
    
    template <typename T>
    using Alloc     = bip::allocator<T, Segment::segment_manager>;
    
    using String    = boost::container::basic_string<char, std::char_traits<char>, Alloc<char> >;
    using KeyType   = String;
    using ValueType = String;
    }
    
  2. Распределители карт были слишком точными. Фактические типы узлов, обертывающие pair<K const, v> элементы на карте в любом случае определены реализацией. Так как карты знают, как распределить эти узлы?

    Oни снова переплетать распределители: см. rebind в документах здесь

    Итак, вы можете просто пройти Alloc<void>, Или тот же распределитель, что и для Shared::String, Карта выяснит это:

    typedef boost::unordered_map<KeyType, ValueType, boost::hash<KeyType>, std::equal_to<KeyType>, Alloc<void> > InMap;
    typedef boost::unordered_map<KeyType, InMap,     boost::hash<KeyType>, std::equal_to<KeyType>, Alloc<void> > OutMap;
    
  3. Теперь для советы по питанию.

    Проходя через распределители состояния, все это безумное время раздражает. Это делает код беспорядком. К счастью, в c ++ 11 (и Boost Containers для c ++ 03) вы уже рассмотрели:

    • scoped_allocator_adaptor<T...>
    • allocator_type
    • uses_allocator<T> черта характера

    Эти помощники могут сделать вашу жизнь намного проще. Они делают это, передавая распределитель вниз конструкторам типа элемента, когда это применимо. Автоматически. Опять же, неявные преобразования из типов распределителя отскока заставляют вещи работать.

    Итак, вы можете на самом деле просто построить одну внешнюю карту с правильным распределителем (сделать это Scoped) и один ключ, и оттуда вам даже не нужно продолжать указывать распределители.

Вот полная демонстрация:

Жить на Колиру

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>

namespace bip = boost::interprocess;

namespace Shared {
using Segment = bip::managed_shared_memory;

template <typename T>
using Alloc   = bip::allocator<T, Segment::segment_manager>;
using Scoped  = boost::container::scoped_allocator_adaptor<Alloc<char> >;

using String  = boost::container::basic_string<char, std::char_traits<char>, Scoped>;
using KeyType = String;

typedef boost::unordered_map<KeyType, String, boost::hash<KeyType>, std::equal_to<KeyType>, Scoped> InMap;
typedef boost::unordered_map<KeyType, InMap,  boost::hash<KeyType>, std::equal_to<KeyType>, Scoped> OutMap;
}

int main() {
srand(time(NULL));

Shared::Segment segment(bip::open_or_create, "BOOST_SHM", 65536);
auto* mgr = segment.get_segment_manager();

Shared::OutMap *p_outside_map = segment.find_or_construct<Shared::OutMap> ("SHM_OUT_MAP") (mgr);
auto& outside_map = *p_outside_map;

Shared::String sskey(mgr); // reduce shared allocations as they are costly (in terms of fragmentation/overhead)

char outer_keys[3], inner_keys[3];
std::generate_n(outer_keys, 3, [] { return rand()%26+'a'; });
std::generate_n(inner_keys, 3, [] { return rand()%26+'a'; });

for (auto key : outer_keys) {
sskey = key;
auto& inner = outside_map[sskey];

for (auto more : inner_keys) {
inner[sskey + "_" + more] += "value";
}
}

for (auto const& oe : outside_map) {
for (auto const& ie : oe.second) {
std::cout << "outside_map[" << oe.first << "][" << ie.first << "] == " << ie.second << "\n";
}
}
}

На самом деле, чтобы он работал на Coliru, нам нужно использовать сопоставленный файл:

Жить на Колиру

Запустите его несколько раз:

outside_map[s][s_t] == value
outside_map[s][s_r] == value
outside_map[s][s_c] == value
outside_map[f][f_t] == value
outside_map[f][f_r] == value
outside_map[f][f_c] == value
outside_map[o][o_t] == value
outside_map[o][o_r] == value
outside_map[o][o_c] == value

Второй прогон:

outside_map[a][a_d] == value
outside_map[a][a_c] == value
outside_map[a][a_g] == value
outside_map[r][r_d] == value
outside_map[r][r_c] == value
outside_map[r][r_g] == value
outside_map[g][g_d] == value
outside_map[g][g_c] == value
outside_map[g][g_g] == value
outside_map[s][s_t] == value
outside_map[s][s_r] == value
outside_map[s][s_c] == value
outside_map[f][f_t] == value
outside_map[f][f_r] == value
outside_map[f][f_c] == value
outside_map[o][o_t] == value
outside_map[o][o_r] == value
outside_map[o][o_c] == value

Обратите внимание, как каждый запуск успешно добавляется value до 9 ключей в 3 внутренних картах.

2

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

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