Подтвердить что ты не робот

Как хранить stl-объекты в общей памяти (С++)?

У меня есть следующий код:

class A {
    double a, b, c;
    ...
};

class B {
    map<int, A> table; // Can have maximum of MAX_ROWS elements.
    ...
};

class C {
    B entries;
    queue<int> d;
    queue<int> e;
    ...
};

Теперь я хочу сохранить объект типа C в общей памяти, чтобы различные процессы могли добавлять, обновлять и читать. Как я могу это сделать? (Примечание. Я знаю, как хранить простой массив C, который имеет фиксированный размер в общей памяти. Также помните, что B.table может иметь произвольные записи.

4b9b3361

Ответ 1

Используйте boost:: interprocess, эта библиотека предоставляет эту функциональность.

EDIT: Вот некоторые изменения, которые вам нужно сделать:

В примере уже описан распределитель, который будет выделяться из блока разделяемой памяти, вам нужно передать это значение в map и queue. Это означает, что вам придется изменить свои определения:

class B
{
  map<int, A, less<int>, MapShmemAllocator> table;

  // Constructor of the map needs the instance of the allocator
  B(MapShmemAllocator& alloc) : table(less<int>(), alloc)
  { }
}

Для queue это немного сложно, потому что он действительно просто адаптер, поэтому вам нужно передать реальный класс реализации в качестве параметра шаблона:

typedef queue<int, deque<int, QueueShmemAllocator> > QueueType;

Теперь ваш класс C слегка изменится:

class C
{
  B entries;
  QueueType d, e;

  C(MapShmemAllocator& allocM, QueueShmemAllocator& allocQ) : entries(allocM), d(allocQ), e(allocQ)
  { }
}

Теперь из диспетчера сегментов создайте экземпляр C с помощью распределителя.

C *pC = segment.construct<C>("CInst")(allocM_inst, allocQ_inst); 

Я думаю, что это должно было сделать трюк. ПРИМЕЧАНИЕ. Вам нужно будет предоставить два распределителя (один для queue и один для map), не уверен, что вы можете построить два распределителя из одного и того же менеджера сегментов, но я не понимаю, почему нет.

Ответ 2

Это может быть сложно. Для начала вам понадобится специальный распределитель: Boost У Interprocess есть один, и я бы начал с него. В вашем точном примере, этого может быть достаточно, но в более общем плане вам необходимо убедиться в том, что все подтипы также используют общую память. Таким образом, если вы хотите строка, для этой строки также потребуется специальный распределитель, что означает что он имеет другой тип, чем std::string, и вы не можете копировать или назначьте его с помощью std::string (но вы можете использовать два итератора конструктор, например:

typedef std::basic_string<char, std::char_traits<char>, ShmemAllocator> ShmemString;
std::map<ShmemString, X, std::less<ShmemString>, ShmemAllocator> shmemMap;

с доступом вроде:

shmemMap[ShmemString(key.begin(), key.end())] ...

И, конечно, любые типы, которые вы определяете, которые входят в карту, также должны использовать разделяемая память для любых распределений: Boost Interprocess имеет offset_ptr, который может помочь здесь.

Ответ 3

Построение и использование STL-объектов в общей памяти еще не сложно (особенно с использованием boost:: interprocess wrappers). Конечно, вы также должны использовать механизмы синхронизации (также не проблема с boost named_mutex).

Реальная задача - сохранить согласованность объектов STL в общей памяти. В принципе, если один из процессов выходит из строя в плохую точку во времени, он оставляет другие процессы с двумя большими проблемами:

  • Заблокированный мьютекс (может быть разрешен с использованием сложных сопоставлений PID-to-mutex, надежных мьютексов (где это возможно), временных мьютексов и т.д.

  • Объект STL в несогласованном состоянии (например, полу-обновленная структура карты во время процедуры erase()). В общем, это еще не восстанавливается, вам нужно уничтожить и перестроить объект в области разделяемой памяти с нуля (возможно, убивая все остальные процессы). Вы можете попытаться перехватить все возможные внешние сигналы в вашем приложении и скрестить пальцы, надеясь, что все будет хорошо, и процесс не завершится неудачно в плохой момент.

Просто помните об этом при принятии решения об использовании разделяемой памяти в вашей системе.