Системное программирование в среде Windows
Шрифт:
Система сериализует вызовы DllMain таким образом, что в каждый момент времени выполнять ее может только один поток (к подробному обсуждению потоков мы приступим в главе 7). Эта сериализация весьма существенна, поскольку операции инициализации, которые должна выполнять DllMain, не должны прерываться до их завершения. По этой же причине внутри точки входа не рекомендуется использовать блокирующие вызовы функций, например, функций ввода/вывода или функций ожидания (см. главу 8), поскольку они будут препятствовать запуску точки входа другими потоками. В частности, не следует вызывать внутри точки входа DLL функции LoadLibrary и LoadLibraryEx,
Функция DisableThreadLibraryCalls отменяет отправку указанному экземпляру DLL уведомлений о подключении и отключении потоков. Запрет отправки уведомлений может пригодиться в тех случаях, когда потоки не нуждаются в каких-либо уникальных ресурсах во время инициализации.
Управление версиями DLL
При использовании DLL обычно проявляются трудности, обусловленные обновлением библиотек за счет введения новых символов и добавления новых средств. Основное преимущество DLL заключается в том, что несколько приложений могут совместно использовать одну и ту же библиотеку, находящуюся в памяти. Вместе с тем, это порождает целый ряд осложнений, связанных с совместимостью версий, что иллюстрируется приведенными ниже примерами.
• В результате добавления новых функций в случае неявного связывания могут стать недействительными смещения, определенные для приложений во время компоновки с .lib-файлами. От этой проблемы можно избавиться, применив явное связывание.
• Поведение новых версий функций может быть иным, в результате чего существующие приложения могут испытывать проблемы, если не будут своевременно обновлены.
• Для приложений, использующих обновленную функциональность DLL, возможны случая связывания с прежними версиями DLL.
Проблемы совместимости различных версий DLL, носящие жаргонное название "кошмара DLL", не являются столь острыми, если в одном каталоге поддерживать только одну версию DLL. Однако предоставить отдельный каталог для каждой из различных версий вовсе не так просто, как может показаться. Существует несколько других вариантов решения этой проблемы.
• Можно использовать номер версии DLL в именах .DLL– и .LIB-файлов, обычно в виде суффикса. Так, чтобы соответствовать номеру версии, используемой в данной книге, в примерах, приведенных на Web-сайте книги, и во всех проектах используются файлы Utility_3_0.LIB и Utility_3_0.DLL. Применяя явное или неявное связывание, приложения могут формулировать свои требования к версиям и получать доступ к файлам с различными именами. Такое решение характерно для UNIX-приложений.
• Компания Microsoft ввела понятие параллельных DLL (side-by-side DLL), или сборок (assemblies) и компонентов (components). При таком подходе в приложение необходимо включать объявление на языке XML, в котором определяются требования к DLL. Рассмотрение этой темы выходит за рамки данной книги, однако дополнительную информацию вы можете получить на Web-сайте компании Microsoft, в разделе, посвященном вопросам разработки приложений.
• Платформа .NET Framework предоставляет дополнительные средства поддержки выполнения приложений в условиях сосуществования различных версий DLL.
В примерах проектов, используемых в данной книге, используется первый из отмеченных подходов, предусматривающий включение номеров версий в имена файлов.
Информация о DLL возвращается в структуре DLLVERSIONINFO, в которой имеются поля типа DWORD для параметров cbSize (размер структуры), dwMajorVersion, dwMinorVersion, dwBuildNumber и dwPlatformID. В последнем поле, dwPlatformID, может быть установлено значение DLLVER_PLATFORM_NT, если библиотека не выполняется под управлением Windows 9x, или DLLVER_PLATFORM_WINDOWS, если это ограничение отсутствует. В поле cbSize должно находиться значение sizeof (DLLVERSIONINFO). В случае успешного выполнения функция возвращает значение NOERROR. Функция DllGetVersion реализована в проекте Utility_3_0.
Резюме
Система управления памятью Windows предоставляет следующие возможности:
• Использование средств Windows, осуществляющих управление кучей, а также обработчиков исключений для обнаружения и обработки ошибок, возникающих при распределении памяти, значительно упрощает логическую организацию.
• Использование нескольких независимых куч обладает рядом преимуществ по сравнению с распределением памяти из одной кучи.
• Методы отображения файлов, доступные в UNIX, но не предоставляемые библиотекой С, обеспечивают обработку файлов в памяти, что было проиллюстрировано несколькими примерами. Отображение файлов в памяти осуществляется независимо от управления кучей и упрощает решение многих задач программирования. Преимущества использования отображения файлов подтверждаются данными о достигаемом за счет этого повышении производительности, приведенными в приложении В.
• DLL являются важным специальным случаем отображения файлов и могут загружаться либо явным, либо неявным образом. DLL, предназначенные для использования многими приложениями, должны предоставлять информацию о версии библиотеки.
В следующих главах
Мы завершили обзор задач, решаемых в рамках одного процесса. Далее мы переходим к изучению методов параллельной обработки, сначала на уровне процессов (глава 6), а затем — потоков (глава 7). В последующих главах показано, как организовать синхронизацию и взаимодействие параллельно выполняющихся операций по обработке данных.
Дополнительная литература
Описание этих важных понятий содержится в книге [38], а их углубленное обсуждение вы можете найти в документации, поставляемой вместе с большинством ОС.
Деревьям поиска и алгоритмам сортировки посвящено множество работ, включая [39] и [34].