Совместное использование данных библиотеки DLL с приложением или другими библиотеками DLL

Обновлен: Ноябрь 2007

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

  • Создание секции именованных данных с помощью указания (прагмы) data_seg.

  • Использование сопоставленных файлов. "Управление сопоставленными в памяти файлами Win32" см. в Библиотеке MSDN.

Пример использования прагмы data_seg:

#pragma data_seg (".myseg")
   int i = 0; 
   char a[32]n = "hello world";
#pragma data_seg()

data_seg используется для создания новой именованной секции (в этом примере — .myseg). Наиболее распространенным является вызов сегмента данных .shared для ясности. Следует указать правильные атрибуты для совместного доступа к вновь созданной секции именованных данных в DEF-файле или в параметре компоновщика /SECTION:.MYSEC,RWS.

Следует принять во внимание следующие ограничения перед использованием сегмента совместного доступа данных:

  • Любая переменная в сегменте совместного доступа данных должна быть статически инициализирована. В вышеприведенном примере, "i" инициализируется значением 0, а "а" инициализируется 32 знаками для "hello world".

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

  • Никогда не следует сохранять информацию о процессах в сегменте данных совместного доступа. Большинство структур данных Win32 или значений (таких как HANDLE) действительны только в контексте одного процесса.

  • Каждый процесс имеет свое собственное адресное пространство. Очень важно то, чтобы указатели никогда не хранились в переменной, находящейся в сегменте данных совместного доступа. Указатель может быть действителен в одном приложении, но не в другом.

  • Возможно, что библиотека DLL загрузится по другому адресу в пространстве виртуальных адресов каждого процесса. Небезопасно объявлять указатели на функции библиотек DLL или на переменные совместного доступа.

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

Сопоставленные в памяти файлы имеют преимущество перед секциями данных совместного доступа, так как начало сопоставленного в памяти файла известно. Разработчики могут реализовывать поведение псевдо-указателя с помощью "смещения от начала секции памяти совместного доступа" во всех данных, расположенных в памяти совместного доступа. Настоятельно рекомендуется для упрощения реализации этого подхода использовать указатели с ключевым словом __based. Тем не менее, важно помнить, что база (или начало сопоставленного в памяти файла) может различаться в каждом процессе, поэтому переменные, хранящие базу для указателей __based, не могут сами быть в памяти совместного доступа.

Эти ограничения являются важными факторами для классов С++.

  • Классы с виртуальными функциями всегда содержат указатели на функции. Классы с виртуальными функциями никогда не должны храниться ни в сегментах данных совместного доступа, ни в сопоставленных в памяти файлах. Это особенно важно для классов MFC или классов, наследованных от MFC.

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

  • Требование к инициализации сегмента данных для совместного доступа вызывает конкретную проблему для классов С++. Если имеется нечто подобное CTest Counter(0); в сегменте данных совместного доступа, объект Counter инициализируется в каждом процессе при загрузке библиотеки DLL, каждый раз потенциально обнуляя данные объекта. Это очень отличается от типов встроенных данных, которые инициализируются компоновщиком при создании библиотеки DLL.

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

Дополнительные сведения о создании секций именованных данных, см. в статьях базы знаний по адресу https://support.microsoft.com.

  • "Совместный доступ к данным между различными сопоставлениями библиотеки DLL" (Q125677).

  • "Выделение данных для совместного доступа и без совместного доступа в библиотеке DLL" (Q100634).

  • "Выделение всех данных для совместного доступа в библиотеке DLL" (Q109619).

  • "Память в секциях кода для совместного доступа не доступна для совместного пользования в сеансах службы терминалов" (Q251045)

См. также

Основные понятия

Вопросы и ответы по библиотекам DLL