Каков наилучший способ инициализации моих глобальных данных в общей библиотеке? - PullRequest
3 голосов
/ 12 августа 2011

У меня есть один класс, который выполняет всю необходимую инициализацию. В настоящее время я объявил глобальный объект этого типа класса, который создается при загрузке библиотеки. Я видел другие способы, такие как удушение

BOOL APIENTRY DllMain

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

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

Ответы [ 4 ]

6 голосов
/ 12 августа 2011

Вот что происходит при запуске C ++ DLL:

  1. Системные вызовы точки входа DLL, сгенерированной вашим компилятором
  2. Точка входа вызывает DllMainCRTStartup (имя может отличаться), которое инициализирует C/ C ++ исполняет и создает все глобальные объекты.
  3. DllMainCRTStartup затем вызывает пользовательский DllMain.

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

DllMain также позволяет вам выполнять инициализацию для каждого потока, чего вы не можете достичьс глобальными объектами.Однако он не переносим на другие платформы.

PS Вам НЕ нужен мьютекс в DllMain, поскольку все вызовы к нему уже сериализованы в критической секции глобального процесса.Т.е. гарантированно два потока не войдут в него одновременно ни для каких целей.Это также причина, почему вы не должны общаться с другими потоками, загружать другие библиотеки и т. Д. Из этой функции;см. MSDN статью для объяснения.

2 голосов
/ 19 августа 2014

Пара вещей, которые никогда не следует делать от DllMain :

  • Вызовите LoadLibrary или LoadLibraryEx (прямо или косвенно). Это может вызвать тупик или сбой.
  • Синхронизация с другими потоками. Это может вызвать тупик.
  • Получить объект синхронизации, который принадлежит коду, который ожидает получения блокировки загрузчика. Это может вызвать тупик.
  • Инициализируйте потоки COM с помощью CoInitializeEx. При определенных условиях эта функция может вызывать LoadLibraryEx.
  • Вызов функций реестра. Эти функции реализованы в Advapi32.dll. Если Advapi32.dll не инициализирован перед вашей DLL, DLL может получить доступ к неинициализированной памяти и вызвать сбой процесса.
  • Вызов CreateProces. Создание процесса может загрузить другую DLL.
  • Вызов ExitThread. Выход из потока во время отсоединения DLL может привести к повторному получению блокировки загрузчика, что приведет к тупику или аварийному завершению.
  • Вызов CreateThread. Создание потока может работать, если вы не синхронизируете его с другими потоками, но это рискованно.
  • Создать именованный канал или другой именованный объект (только для Windows 2000). В Windows 2000 именованные объекты предоставляются библиотекой служб терминалов. Если эта DLL не инициализирована, вызов DLL может привести к сбою процесса.
  • Используйте функцию управления памятью из динамического C-Run-Time (CRT). Если библиотека CRT не инициализирована, вызовы этих функций могут привести к сбою процесса.
  • Вызов функций в User32.dll или Gdi32.dll. Некоторые функции загружают другую DLL, которая не может быть инициализирована.
  • Использовать управляемый код.
1 голос
/ 12 августа 2011

Вам нужна статическая логическая переменная инициализации и мьютекс .Статически инициализируйте «initialized» в 0. В вашем DllMain () сделайте вызов CreateMutex ().Используйте bInitialOwner = 0 и уникальное имя для lpName, уникальное для вашего приложения.Затем используйте WaitForSingleObject () для ожидания мьютекса.Проверьте, не инициализировано ли ненулевое значение.Если нет, выполните инициализацию, а затем установите значение initialized в 1. Если значение initialized не равно нулю, ничего не делайте.Наконец, освободите мьютекс, используя ReleaseMutex (), и закройте его, используя CloseHandle ().

Вот некоторый псевдокод, без обработки ошибок и исключений:

initialized = 0;

DllMain()
{
    mutex = CreateMutex(..., 0, "some-unique-name");
    result = WaitForSingleObject(handle, ...);
    if (result == WAIT_OBJECT_0) {
        if (!initialized) {
            // initialization goes here
            initialized = 1;
        }
    }
    ReleaseMutex(mutex);
    CloseHandle(mutex);
}
0 голосов
/ 12 августа 2011

привет, я бы порекомендовал вам предпочесть класс signleton, где вы можете создать только один объект класса и использовать его.Класс Sigleton может быть создан с помощью частного конструктора.Теперь предположим, что ur class A является одноэлементным классом, его объект может использоваться в конструкторе каждого класса, который вы хотите инициализировать.Пожалуйста, дайте нам пример кода, чтобы другие могли помочь вам лучше.

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