Создайте вектор строк с общей памятью

Я пытаюсь создать класс, управляющий вектором (std) строк в общей памяти.

typedef boost::interprocess::allocator<std::string, boost::interprocess::managed_shared_memory::segment_manager> shmem_allocator;
typedef boost::interprocess::vector<std::string, shmem_allocator> shmem_vector;

shmem_mgr::shmem_mgr() :
    shmem_(create_only, SHMEM_KEY, SHMEM_SIZE),
    allocator_(shmem_.get_segment_manager())
{
    mutex_  = shmem_.find_or_construct<interprocess_mutex>(SHMEM_MUTEX)();
    condition_ = shmem_.find_or_construct<interprocess_condition>(SHMEM_CONDITION)();
    //buffer_ is of type shmem_vector
    buffer_  = shmem_.construct<shmem_vector>(SHMEM_BUFFER_KEY)(allocator_);
}

void shmem_mgr::run() {
    running_ = true;

    while(running_) {
        scoped_lock<interprocess_mutex> lock ( *mutex_ );

        int size = buffer_->size();

        log_.debug() << size << " queued request(s) found" << std::endl; //LINE 27
        for(int i=0; i<size; i++) {
            log_.debug() << buffer_->at(i); // at() crashes my app
        }

        buffer_->clear(); //so does clear()
        condition_->wait (lock);
    }
}

Клиент успешно добавляет строку в вектор (ему также удается прочитать эту строку из буфера для отладки), менеджер (код выше) получает сигнал (переменная condtion), пишет, что в векторе есть строка (строка 27 ), но когда он пытается получить эту строку через at(), приложение вылетает.


Изменить: Я понял, что использование std::string невозможно, для этого случая есть контейнер string в boost ipc. Это не меняет того факта, что мне нужен вектор строк (boost / std) ...


В: Как передать строки через общую память? Мне нужно сохранить их в некотором буфере (способном хранить> 1 за раз) в shmem, а затем получить второй процесс - это требование. Вход всегда std::string, как и выход, но внутреннее представление в shmem может быть другим.


person emesx    schedule 19.10.2012    source источник
comment
Где меня объявляют? Разве ты не хочешь этим воспользоваться?   -  person imreal    schedule 19.10.2012
comment
нет, просто глупая опечатка. Фиксированный.   -  person emesx    schedule 19.10.2012
comment
@elmes: Все еще неправильно, вы передаете итератор at(), но at() принимает только std::vector<T>::size_type. Даже если бы этот код компилировался (а не компилировался), это не имело бы смысла. Также немного странно, что log.debug() возвращает lvalue, которое должно использоваться таким образом ... зачем вам передавать аргумент?   -  person Ed S.    schedule 19.10.2012
comment
1. Это обязательно должен быть вектор? 2. Нужно ли в разделяемой памяти хранить строки или достаточно для хранения указателей на строки? 3. Нужен ли вам одновременный доступ (я полагаю, не из-за использования мьютекса)? 4. Должен ли код быть кроссплатформенным? Вы, наверное, уже знаете, что стандартные итераторы не являются потокобезопасными. Если вы ответите на вышеперечисленные вопросы, я могу предложить решение.   -  person Ian Thompson    schedule 23.10.2012
comment
1. Не обязательно, но произвольный доступ да. 2. У меня есть вариант использования, когда на входе у меня есть std :: string, а на выходе мне нужна std :: string (2-й процесс) 3. Я не могу запретить одновременное использование. Mutex предназначен для conditon, и условие состоит в том, чтобы не тратить время процессора (но ждать другого ввода в процессе потребителя) 4. Да!   -  person emesx    schedule 23.10.2012
comment
Чтобы быть точным, мне нужно отправить полиморфные классы (хранящиеся с помощью указателей базового класса) через 2 процесса. Boost на это не способен, поэтому я преобразовываю эти объекты в строки.   -  person emesx    schedule 23.10.2012
comment
Я все еще не понимаю, для чего нужен мьютекс. Вы не показываете код / ​​функцию, которая помещает строки в общую память. У вас есть блокировка мьютекса в функции push string? Что касается передачи подклассов, можете ли вы сохранить тип подобъекта в самом объекте и использовать dynamic_cast для приведения объекта в приемник? И последний вопрос, кто распоряжается «объектами» / строками? Это приемник? Или вектор продолжает расти, пока не исчерпает память?   -  person Ian Thompson    schedule 23.10.2012
comment
да, мьютекс используется в клиентах при добавлении строк и для запуска условия, чтобы потребитель мог отреагировать. Когда получатель просыпается от waiting по условию, он получает все новые строки, обрабатывает их и удаляет из вектора. Потом снова wait ..   -  person emesx    schedule 23.10.2012


Ответы (3)



вам нужен собственный распределитель для ваших общих классов stl. вам нужен самодостаточный указатель (они есть в ACE и boost), определенный в распределителе. На противоположных сторонах (НЕПРЕРЫВНАЯ) разделяемая память обычно находится по разным адресам. Вам также нужна подсистема распределения общей памяти (диспетчер кучи) (которую выделяет распределитель) - весь нетривиальный низкоуровневый код, но определенно выполнимый, и как только он у вас есть, его можно использовать везде. Если вы сделаете все это, вам нужно только передать смещение (от начала (НЕПРЕРЫВНОЙ !!) области кучи) неплоской структуры вокруг.

Вы можете создавать очереди и все остальное, что вам может понадобиться - все при условии, что «указатели» в объектах являются самодостаточными и что несмежные части в ваших неплоских частях происходят из одной большой смежной части.

Вы не можете использовать std :: string, потому что, если вы не контролируете распределение, память в стандартной строке НЕ имеет НИЧЕГО общего с вашей общей памятью - то же самое для любой другой структуры stl

Также обязательно (как обычно) решить / согласовать вопросы собственности.

person pgast    schedule 20.10.2012
comment
В порядке. Как насчет boost::interproces::vector из boost::interprocess::string или любого другого вектора некоторых строк? Мне нужно передать некоторые строки через 2 процесса, что мне делать - person emesx; 21.10.2012

Вы можете использовать boost :: interprocess :: managed_shared_memory. Следующая программа передает boost :: interprocess :: string между двумя процессами. Прекрасно работает на моей машине (Ubuntu Linux). Вы можете использовать managed_shared_memory для передачи векторов или объектов. boost :: interprocess :: string имеет метод c_str ().

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <cstring>
#include <cstdlib>
#include <string>
#include <iostream>

int main(int argc, char *argv[])
{
  using namespace boost::interprocess;
  typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
  typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> string;
  if(argc == 1){  //Parent process

      boost::interprocess::shared_memory_object::remove("MySharedMemory");

      //Create a shared memory object.
      managed_shared_memory shm (create_only, "MySharedMemory", 1024);

      string *s = shm.find_or_construct<string>("String")("Hello!", shm.get_segment_manager());
      std::cout << *s << std::endl;

      //Launch child process
      std::string s1(argv[0]); s1 += " child ";
      if(0 != std::system(s1.c_str()))
         return 1;
  }
  else{
      //Open already created shared memory object.
      managed_shared_memory shm (open_only, "MySharedMemory");
      std::pair<string *,std::size_t> ret = shm.find<string>("String");
      std::cout << *(ret.first) << std::endl;
  }
  return 0;
}
person John Qualis    schedule 25.10.2012