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

Внутри 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"


person DragonX    schedule 25.11.2015    source источник
comment
@sehe Привет, не могли бы вы немного уточнить, некоторые указатели были бы действительно полезны. Также я не знаком с livecoding.tv/sehe (каждый раз показывает офлайн)   -  person DragonX    schedule 25.11.2015
comment
Результат работы, конечно, выложу. Жаль, что ты не видишь поток тогда   -  person sehe    schedule 25.11.2015


Ответы (1)


Ok.

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

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

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


  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> элементы в карту, в любом случае определяются реализацией. Итак, как карты узнают, как распределять эти узлы?

    Они повторно связывают распределители: см. rebind < / a> в документации здесь

    Итак, вы можете просто передать 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) и одним ключом, и оттуда вам даже не придется постоянно указывать распределители.

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

Live On Coliru

#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, нам нужно вместо этого использовать сопоставленный файл:

Live On 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 внутренних картах.

person sehe    schedule 25.11.2015
comment
Мне было весело создавать этот образец. Если вы хотите просмотреть записанный прямой эфир: livecoding.tv/ video / interprocess-nested-maps-scoped-allocators (есть некоторые отвлекающие и конструктивные шумы, но вы знаете ... Всякое бывает :)) - person sehe; 25.11.2015
comment
PS. Обратите внимание, что sskey + "_" + more довольно неэффективен. Было бы лучше постоянно использовать один и тот же Shared::String экземпляр. Не могли бы вы сообщить мне, был ли вам полезен этот ответ? - person sehe; 25.11.2015
comment
в этом некоторые реализации для меня новы. Мне нужно пройти через это и внедрить в настоящий проект в соответствии с требованиями. Тогда я могу быть уверен в этом. Пока образец работает нормально :) - person DragonX; 25.11.2015
comment
Привет, livecoding.tv/pastebin/xByA, подскажите, пожалуйста, правильный ли это подход? Также у меня есть несколько сомнений, например, перегружен ли [] для поиска на карте и как обрабатывать недопустимый ключ на обеих картах? - person DragonX; 27.11.2015
comment
Ты умеешь читать свой код? Я не могу. Это плохой знак. Никогда не пишите подобный код. Вопрос о том, правильный ли это подход, не имеет смысла. Это c ++, а не сборка. Я прочитаю его сейчас и попытаюсь расшифровать, что он делает. В следующий раз подумайте о том, чтобы задать новый вопрос. \ - person sehe; 27.11.2015
comment
Вот не менее 8 различных подходов, которые могут вам подойти: Live On Coliru ‹/Kbd›. Обратите внимание, что руководящим принципом для всего этого был: как я хочу, чтобы код выглядел. И как мне избежать повторения одной и той же информации. Только после этого как я могу избежать создания / выделения временных файлов. (Также обратите внимание, не было вопросов, как мне избежать путаницы в переменных m1, u3, s17 ... потому что ... вы никогда этого не делаете :)) - person sehe; 27.11.2015
comment
да, я знаю, но я просто тестировал это. Фактическая реализация в исходном коде чище, чем эта. , эй, если ты не возражаешь, есть ли какой-нибудь способ связаться с тобой (кроме SO и livecoding.tv)? Спасибо за помощь :) - person DragonX; 27.11.2015
comment
Я возражаю. Есть причина, по которой я нахожусь на SO. Идея заключается в том, что помощь одному человеку помогает другим. Также нет личной зависимости (если я не в настроении, может помочь кто-то другой). У меня нет причин уходить за пределы площадки. - person sehe; 27.11.2015
comment
(PS. Если реальная реализация в исходном коде чище, чем эта - почему вы спросили комментарий?) - person sehe; 27.11.2015
comment
хотел знать логику - person DragonX; 28.11.2015
comment
Привет, у меня есть сомнения в Shared::String sskey(mgr);, если sskey объявлен и инициализирован с использованием mgr в функции foo(), тогда, когда foo() выходит за пределы области действия / разворачивается, будет ли sskey правильно уничтожаться в общей памяти во время каждого последующего вызова foo()? Итак, sskey находится в общей памяти или в стеке foo()? - person DragonX; 04.12.2015
comment
@DragonX Оба, именно так std::string обычно работает. Строковый объект находится там, где / вы / его поместили (в данном случае в локальном стеке). Распределитель используется для выделения непрерывной памяти для хранения значения строки (ничего из этого не является особенным для общей памяти, вы просто могли не задумываться об этом раньше). Деструктор поступает правильно. - person sehe; 04.12.2015