Увеличение, общая память и векторы - PullRequest
6 голосов
/ 24 апреля 2009

Мне нужно разделить стек строк между процессами (возможно, более сложными объектами в будущем). Я решил использовать boost :: interprocess, но не могу заставить его работать. Я уверен, что это потому, что я чего-то не понимаю. Я последовал их примеру, но я был бы очень признателен, если бы кто-то, имеющий опыт использования этой библиотеки, мог взглянуть на мой код и сказать мне, что не так. Проблема, кажется, работает, но после нескольких итераций я получаю всевозможные исключения как для процесса чтения, так и иногда для процесса записи. Вот упрощенная версия моей реализации:

using namespace boost::interprocess;
class SharedMemoryWrapper
{
public:
    SharedMemoryWrapper(const std::string & name, bool server) :
      m_name(name),
      m_server(server)
    {
        if (server)
        {
            named_mutex::remove("named_mutex");
            shared_memory_object::remove(m_name.c_str());
            m_segment = new managed_shared_memory (create_only,name.c_str(),65536);         
            m_stackAllocator = new StringStackAllocator(m_segment->get_segment_manager());
            m_stack = m_segment->construct<StringStack>("MyStack")(*m_stackAllocator);
        }
        else
        {
            m_segment = new managed_shared_memory(open_only ,name.c_str());
            m_stack = m_segment->find<StringStack>("MyStack").first;
        }
        m_mutex = new named_mutex(open_or_create, "named_mutex");
    }

    ~SharedMemoryWrapper()
    {
        if (m_server)
        {
            named_mutex::remove("named_mutex");
            m_segment->destroy<StringStack>("MyStack");
            delete m_stackAllocator;
            shared_memory_object::remove(m_name.c_str());
        }
        delete m_mutex;
        delete m_segment;
    }

    void push(const std::string & in)
    {
        scoped_lock<named_mutex> lock(*m_mutex);
        boost::interprocess::string inStr(in.c_str());
        m_stack->push_back(inStr);
    }
    std::string pop()
    {
        scoped_lock<named_mutex> lock(*m_mutex);
        std::string result = "";
        if (m_stack->size() > 0)
        {
            result = std::string(m_stack->begin()->c_str());
            m_stack->erase(m_stack->begin());
        }
        return result;
    }
private:
    typedef boost::interprocess::allocator<boost::interprocess::string, boost::interprocess::managed_shared_memory::segment_manager> StringStackAllocator;
    typedef boost::interprocess::vector<boost::interprocess::string, StringStackAllocator> StringStack;
    bool m_server;
    std::string m_name;
    boost::interprocess::managed_shared_memory * m_segment;
    StringStackAllocator * m_stackAllocator;
    StringStack * m_stack;  
    boost::interprocess::named_mutex * m_mutex;
};

РЕДАКТИРОВАТЬ Отредактировано для использования named_mutex. Оригинальный код использовал interprocess_mutex, что неверно, но это не проблема.

EDIT2 Я также должен отметить, что все работает до определенной степени. Процесс записи может выдвинуть несколько небольших строк (или одну очень большую строку) до того, как читатель прервется. Читатель ломается таким образом, что строка m_stack-> begin () не ссылается на допустимую строку. Это фигня. И тогда дальнейшее исполнение выдает исключение.

EDIT3 Я изменил класс, чтобы использовать boost :: interprocess :: string вместо std :: string. Тем не менее, читатель не работает с неверным адресом памяти. Вот читатель / писатель

//reader process
SharedMemoryWrapper mem("MyMemory", true);
std::string myString;
int x = 5;
do
{
    myString = mem.pop();
    if (myString != "") 
    {
        std::cout << myString << std::endl;
    }
} while (1); //while (myString != ""); 

//writer
SharedMemoryWrapper mem("MyMemory", false);
for (int i = 0; i < 1000000000; i++)
{
    std::stringstream ss;
    ss <<  i;  //causes failure after few thousand iterations
    //ss << "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" << i; //causes immediate failure
    mem.push(ss.str());
}
return 0;

Ответы [ 2 ]

4 голосов
/ 13 июля 2009

Есть несколько вещей, которые выскочили на меня о вашей реализации. Одним из них было использование указателя на именованный объект мьютекса, тогда как документация большинства библиотек надстройки имеет тенденцию отклоняться назад, чтобы не использовать указатель. Это заставляет меня попросить дать ссылку на фрагмент программы, из которой вы работали при создании собственного тестового примера, поскольку у меня были подобные неудачи, и иногда единственным выходом было возвращаться к образцу и двигаться вперед по одному шагу за раз, пока Я сталкиваюсь с переломным изменением.

Другая вещь, которая кажется сомнительной, это то, что вы выделили блок 65k для разделяемой памяти, а затем в своем тестовом коде зациклились до 1000000000, вставляя строку в ваш стек каждую итерацию.

С современным ПК, способным выполнять 1000 инструкций в микросекунду и более, и операционными системами, такими как Windows, все еще выделяются кванты выполнения за 15 миллисекунд. куски, это не займет много времени, чтобы переполнить этот стек. Это было бы мое первое предположение о том, почему вещи Haywire.

P.S. Я только что вернулся от фиксации своего имени к чему-то, напоминающему мою настоящую личность. Тогда ирония ударила, что мой ответ на ваш вопрос пялился на нас обоих в левом верхнем углу страницы браузера! (То есть, конечно, предполагая, что я был прав, что часто не так в этом бизнесе.)

0 голосов
/ 24 апреля 2009

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

...