Совместное использование памяти между модулями - PullRequest
9 голосов
/ 06 января 2011

Мне было интересно, как разделить некоторую память между различными программными модулями - скажем, у меня есть основное приложение (exe), а затем какой-то модуль (dll).Они оба ссылаются на одну и ту же статическую библиотеку.Эта статическая библиотека будет иметь некоторый менеджер, который предоставляет различные сервисы.Я хотел бы добиться того, чтобы этот менеджер был общим для всех модулей приложения, и делать это прозрачно во время инициализации библиотеки.Между процессами я мог бы использовать разделяемую память, но я хочу, чтобы это делилось только в текущем процессе.Не могли бы вы придумать какой-нибудь кроссплатформенный способ сделать это?Возможно использование библиотек boost, если они предоставляют некоторые возможности для этого.

Единственное решение, о котором я могу подумать сейчас, - это использовать разделяемую библиотеку соответствующей ОС, с которой все другие модули будут ссылаться во время выполнения, исохраните там менеджерспособы сделать это)

Получить указатель на менеджера, если он существует, или Установить указатель где-то на вновь созданный объект менеджера.

Ответы [ 4 ]

11 голосов
/ 06 января 2011

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

Однако, если вы хотите вызывать API-интерфейсы ОС, это выполнимо, и я думаю, что вам могут понадобиться только две реализации специфичной для ОС части (одна для Windows DLL и GetProcAddress, другая для ОС, использующих dlopen).

Когда каждый модуль загружается, он просматривает список ранее загруженных модулей, ища те, которые экспортируют функцию с особым именем. Если он находит один (любой, не имеет значения, какой, поскольку инвариант состоит в том, что все полностью загруженные модули знают об общем объекте), он получает адрес общего объекта из ранее загруженного модуля, а затем увеличивает счетчик ссылок. , Если он не может их найти, он распределяет новые данные и инициализирует счетчик ссылок. Во время выгрузки модуля он уменьшает счетчик ссылок и освобождает общий объект, если счетчик ссылок достиг нуля.

Конечно, необходимо использовать распределитель ОС для общего объекта, потому что, хотя это маловероятно, возможно, что он освобожден из библиотеки, отличной от той, которая его первой загрузила. Это также подразумевает, что общий объект не может содержать какие-либо виртуальные функции или любые другие указатели на сегменты различных модулей. Все его ресурсы должны быть динамически распределены с использованием распределителя процесса всей ОС. Это, вероятно, меньше нагрузки на системы, где libc ++ является разделяемой библиотекой, но вы сказали, что статически связываете CRT.

Функции, необходимые в Win32, включают EnumProcessModules, GetProcAddress, HeapAlloc и HeapFree, GetProcessHeap и GetCurrentProcess.

Учитывая все вышесказанное, я думаю, что я бы придерживался того, чтобы поместить общий объект в его собственную разделяемую библиотеку, которая использует структуры данных загрузчика, чтобы найти его. В противном случае вы заново изобретаете загрузчик. Это будет работать, даже если CRT статически связан в несколько модулей, но я думаю, что вы настраиваете себя на нарушения ODR. Будьте особенно внимательны при хранении общих данных POD.

1 голос
/ 06 января 2011

Для использования только из текущего процесса вам не нужно придумывать какую-либо специальную функцию или структуру.

Вы можете сделать это даже без какой-либо функции, но это более безопасно и кросс-платформенно, чтобы определить наборфункций, обеспечивающих доступ к общим данным.И эти функции могут быть реализованы общей статической библиотекой.

Я думаю, единственное беспокойство этой установки заключается в том, что: «Кто будет владеть данными?».Должен существовать один и только один владелец общих данных.

С этой базовой идеей мы могли бы сделать набросок API следующим образом:

IsSharedDataExist     // check whether of not shared data exist

CreateSharedData      // create (possibly dynamically) shared data

DestroySharedData     // destroy shared data

... various data access API ...

Или класс C ++ с шаблоном Singleton будетсоответствующий.


ОБНОВЛЕНИЕ

Я был смущен.Реальная проблема может быть определена как «Как реализовать класс Singleton в статической библиотеке, которая будет связана с несколькими библиотеками динамической загрузки (будет использоваться в том же процессе) независимо от платформы».

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

Для этой цели вы можете использовать Boost.Interprocess.

#include <boost/config.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
...
boost::interprocess::named_mutex* singleton_check = 0;

// in the Create function of the singleton
try {
    singleton_check = new boost::interprocess::named_mutex(boost::interprocess::create_only, "name_of_the_mutex" );
    // if no exception throw, this is the first time execution
}
catch (...)
{
}

Освобождениеnamed_mutex так же прост, как delete singleton_check.


ОБНОВЛЕНИЕ # 2

Еще одно предложение.

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

Если вы предпочитаете реализацию статической библиотеки, вам следует создать две статические библиотеки.Один для сервера / создателя общих данных, один для пользователей этих общих данных.Серверная библиотека определяет и обеспечивает доступ к Синглтону.Клиентская библиотека предоставляет различные методы доступа к данным.

Это практически то же самое, что реализация Singleton без статических библиотек.

0 голосов
/ 21 августа 2013

Согласно MSDN Я вижу, что есть только два способа обмена данными между модулями

  1. Использование data_seg pragma
  2. Использовать разделяемую память.

Как кто-то указал, Shared Segment работает только для двух экземпляров одной и той же библиотеки DLL, поэтому у нас остается только один выбор - использовать метод Memory-Mapped Files.

0 голосов
/ 06 января 2011

Вы можете использовать boost::interprocess http://www.boost.org/doc/libs/1_45_0/doc/html/interprocess.html а в Windows вы можете создать общий сегмент в вашей DLL, который будет использоваться всеми процессами, используя # pragma's: http://www.codeproject.com/KB/DLL/data_seg_share.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...