- •36. Подсистема Win32. 32-х разрядный api. Подсистема Win32
- •37. Структура.
- •38. Конструктивные изменения.
- •39. Api: ms-dos и 16-ти разрядной Windows. Виртуальные dos-машины. Api: ms-dos и 16-ти разрядной Windows.
- •Виртуальные dos-машины
- •44. Диспетчер. Виртуальная память. Диспетчер.
- •Виртуальная память
- •45. Средства пользовательского режима: управление памятью, совместное использование. Средства пользовательского режима
- •Управление памятью
- •Совместное использование памяти
- •46. Совместное использование: секции, проекции и проецируемые файлы. Секции, проекции и проецируемые файлы
- •47. Объект-секция. Способы защиты памяти. Объект-секция
- •Защита памяти
- •48. Собственная память процесса. Совместное использование памяти. Собственная память процесса
- •Совместное использование памяти
- •49. Адресное пространство. Подкачка страниц. Адресное пространство
- •Подкачка страниц
- •50. Механизмы подкачки страниц. Механизмы подкачки страниц
- •51. Стратегия подкачки и рабочие наборы. Стратегия подкачки и рабочие наборы
38. Конструктивные изменения.
MS DOS/Windows — это маленькая, простая ОС. Она предназначалась для работы на персональных компьютерах с небольшим объемом памяти и, конечно, не имевших быстрых современных процессоров Intel и RISC. На маленьких компьютерах, где имеет значение каждый байт и каждый цикл процессора, было бы непрактично делать Windows полностью надежной средой, так как обеспечение этого требует определенной платы — размером и скоростью выполнения кода.
С другой стороны, Windows NT разрабатывалась как ОС, которая может обслуживать произвольное число пользователей в сети и выполнять сложные банковские или важные правительственные приложения. В средах такого типа возможность того, что одно приложение повредит другим приложениям или "подвесит" ОС, неприемлема. Таким образом, устойчивость была важной целью при создании подсистемы Win32.
Чтобы защитить ОС от приложений, диспетчер окон Win32 должен работать несколько иначе, нежели старый диспетчер окон. Группа разработчиков диспетчера окон должна была сделать 32-разрядную версию более устойчивой и надежной средой, чем 16-разрядный диспетчер окон. Основные изменения были следующими:
Рис. 5-14. Модель ввода 16-разрядной Windows.
• десинхронизация модели ввода Windows;
• схема вытесняющего планирования потоков;
• добавление проверки описателей объектов и блокировок объектов.
Первое изменение связано с тем, как подсистема Win32 обрабатывает пользовательский ввод (с нажатиями клавиш и кнопок мыши). Модель ввода 16-разрядного диспетчера окон была синхронной, т. е. весь пользовательский ввод помещался в одну очередь ("первым пришел, первым обслужен") и посылался приложениям тогда, когда они его запрашивали. После ввода пользователь должен был ждать, пока приложение его обработает, прежде чем мог быть обработан последующий ввод. Так как в данный момент времени выборку ввода могло осуществлять только одно приложение, каждое из них должно было своевременно выбирать ввод из очереди, чтобы все приложения выполнялись без помех. Синхронная модель ввода показана на рис. 5-14.
Иногда при
использовании этой модели возникали
проблемы. Какое-нибудь приложение
могло "зависнуть" и перестать
выбирать ввод или не имело возможности
выбирать его быстро из-за сильной
занятости. В таких случаях работа других
приложений останавливалась, так
Рис. 5-15. Модель ввода Win32.
как они не получают данных , необходимых для продолжения. С точки зрения пользователя это выглядело как "зависание" ОС'.
Потребовалась значительная переделка модели ввода 16-разрядного диспетчера окон, но в результате устойчивость подсистемы Win32 сильно повысилась. В новой модели ввода каждое приложение имеет отдельную очередь ввода, как показано на рис. 5-15.
При получении пользовательского ввода подсистема Win32 немедленно определяет, для какого приложения он предназначен (проверяя, какое окно является в данный момент активным, и где расположен указатель мыши), 32-разрядный диспетчер окон помещает ввод в соответствующую очередь ввода, и приложение выбирает его по мере своей готовности. Если по некоторой причине приложение прекратило выборку ввода, то на других программах это не отражается.
Вторым существенным изменением в подсистеме Win32, по сравнению с 16-разрядной Windows, является полная поддержка вытесняющей многозадачности. В устойчивой ОС неприемлема ситуация, когда одно приложение перестает работать, и у ОС нет способа вмешаться или завершить исполнение приложения. 16-разрядная Windows рассчитывает на то, что приложения время от времени сами освобождают процессор, позволяя выполняться другим программам, но это не всегда имеет место в действительности. В Windows NT подсистема Win32 (опираясь на существенную поддержку ядра NT) вынуждает приложения освобождать процессор. Каждый поток приложения может выполняться только на протяжении выделенного ему кванта времени. После этого ядро NT прерывает выполнение потока и проверяет, есть ли необходимость исполнения потока с более высоким приоритетом.
Используя вытеснение, подсистема Win32 не только вынуждает приложения освобождать процессор, но может и принудительно завершить приложение Win32. Например, если приложение зависло из-за ошибки в нем или если пользователь просто не хочет больше ждать, он может воспользоваться кнопкой End Task (Завершить задачу) в Windows Task Manager. Работая в 16-разрядной Windows, ошибочное приложение может не допустить своего завершения или, в особо тяжелых случаях, даже не дать Task Manager отобразить свое окно на экране. В Windows NT, однако, подсистема Win32 обращается для принудительного завершения приложения к исполнительной системе NT, и это обращение всегда успешно. Поскольку поток приложения построен на основе объекта-потока NT, диспетчер процессов посылает сообщения в порт завершения потока. Подсистема среды, отвечающая за данное приложение, получает это сообщение и освобождает любую поддерживаемую ею глобальную информацию относительно завершенного приложения.
Кроме десинхронизации модели ввода и реализации вытеснения, подсистема Win32 выполняет проверку описателей объектов. В 16-разрядной Windows описатели объектов иногда вызывали проблему, так как ОС предполагала, что приложения всегда передают ей правильные описатели — т. е. такие, которые на самом деле являются ссылками на те объекты, на которые должны указывать. Если же вместо описателя окна приложение передавало нечто постороннее, системное программное обеспечение могло сбоить.
В противоположность этому, подсистема Win32 проверяет содержимое описателей, передаваемых приложениями. Как и описатель объекта NT, описатель объекта Win32 — это индекс в таблице. Описатель и соответствующий ему элемент таблицы содержат определенную информацию об объекте, на который ссылается описатель. Подсистема Win32 в состоянии проверить, что описатель указывает на объект именно того типа, который требуется. Она даже может определить, что описатель указывает на нужный экземпляр данного типа. В добавление к проверке описателей, Win32 реализует разновидность удержания объектов, аналогичную той, что используется исполнительной системой NT. В 16-разрядной Windows приложение могло уничтожить объект, который все еще используется ОС, что вело к системным ошибкам. Подсистема же Win32 поддерживает для необходимых ей объектов счетчик ссылок. Приложение по-прежнему может "удалить" объект, но система не уберет его из памяти до тех пор, пока он продолжает использоваться.
Компонент GDI Win32 не является просто модернизацией 16-разрядной версии — он полностью переписан. Первой задачей для компонента GDI подсистемы Win32 была замена ассемблерного кода переносимым кодом на С, а также реорганизация внутренней работы для поддержки некоторых продвинутых возможностей. В состав новых средств GDI входят кривые Безье, дающие пользователям графических пакетов более тонкие средства рисования дуг; траектории (paths), позволяющие создавать объекты произвольной формы при помощи последовательности команд рисования; трансформация объектов, дающая возможность приложениям выполнять отображение из одного координатного пространства в другое; и наконец, корреляция объектов, средство, при помощи которого приложение может легко определить, перекрывается ли данный объект или область с другими. Другим конструктивным изменением в GDI Win32 является новый интерфейс драйвера устройства. Этот интерфейс превосходит по своим возможностям обоих предшественников, давая более тонкие способы контроля драйверам графических устройств Win32 (которые отвечают за создание изображений в аппаратно-зависимом формате и посылку их на устройства вывода). В частности, GDI настраивает данные, которые он посылает драйверу устройства, в зависимости от набора понятных драйверу операций. Например, если данный драйвер "понимает" кривые Безье, то GDI передает их ему целиком. В противном случае GDI разбивает кривую на простые линейные сегменты, прежде чем послать ее драйверу. Кроме того, в GDI включены новые мощные функции создания битовых изображений, которые программисты могут, в частности, использовать при создании драйверов дисплеев и принтеров вместо того, чтобы писать свои собственные функции. Благодаря этой поддержке значительно сокращается время написания и отладки драйверов устройств. Разработчики могут возложить на GDI большую часть работы, добавляя в драйвер устройства только аппаратно-зависимые расширения и оптимизации.
Несмотря на все упомянутые выше улучшения, возможно, самым большим изменением как в диспетчере окон, так и в GDI, была реализация Win32 в виде защищенной подсистемы, т. е. в виде серверного процесса. Разработчики каждой из подсистем среды Windows NT разделили процедуры своих API на две группы — те, которые используют только локальные данные, и те, которые используют глобальные данные. Первая группа в целях повышения производительности может быть реализована в DLL клиентской стороны. Вторая же должна быть реализована в адресном пространстве подсистемы, чтобы глобальные данные оставались защищенными, но по-прежнему доступными всем клиентам подсистемы. Это изменение повлияло на выбор способа написания приложения Win32, особенно в случае вызова функций GDI.
Хотя GDI рассматривает почти все данные как локальные в клиентском процессе, при прорисовке объектов все процессы совместно используют одно устройство вывода — экран. Таким образом, экран фактически относится к "глобальным данным", и функции GDI, изменяющие его состояние, должны быть реализованы в сервере Win32, а не в DLL клиентской стороны. Чтобы обеспечить для этих функций максимальную скорость работы, GDI применяет несколько оптимизаций. Например, чтобы изменить цвета на экране, приложение может вызвать функцию GDI для установки цвета переднего плана, затем снова вызвать GDI для установки цвета фона, после чего выполнить еще несколько операций, прежде чем рисовать что-либо на экране. Вместо того, чтобы вызывать подсистему при каждом вызове функции GDI, DLL сохраняет измененную информацию в собственном буфере. Когда приложение рисует что-нибудь на экране, DLL посылает подсистеме все измененные данные одним сообщением. В представленном здесь примере подсистема обновила бы цвета экрана в DLL, подождав с посылкой информации об изменениях серверу до тех пор, пока не будет выдан первый запрос на рисование. Кэширование атрибутов (attribute cashing), как называется этот метод буферизации, минимизирует количество переключении контекста и объем времени, затраченный на передачу сообщений между клиентом и сервером.
Для уменьшения числа переключений контекста между клиентом и сервером GDI использует аналогичный способ оптимизации, пакетирование (batching). Пакетирование — это метод, при использовании которого, например, DLL GDI сохраняет несколько вызовов функций в очереди и посылает их на сервер одним сообщением, когда очередь переполняется или когда пользователь выполняет ввод. При получении такого сообщения сервер Win32 последовательно выполняет все функции, прежде чем управление возвращается клиенту. Прежде чем использовать эту технику, разработчики GDI провели тесты и проверили, не будет ли вывод на экран прерывистым или неравномерным. Тесты показали, что вызовы функций посылаются серверу достаточно часто, и вывод на экран проходит плавно и ровно.
Авторам прикладных программ следует иметь в виду эти методы оптимизации производительности при создании новых многопоточных приложений. Если два потока работают вместе, то их исполнение должно быть синхронизировано, чтобы гарантировать выполнение действий в надлежащем порядке. Например, нужно учитывать, что результат не появится на экране сразу же после вызова потоком функции API. Вызов функции может сохранен в буфере потока, ожидая своего вывода на экран. GDI предоставляет функцию GdiFlush(), при помощи которой поток может осуществить принудительную посылку кэшированных вызовов функций на сервер Win32.
Другим результатом использования модели клиент-сервер является то, что приложения, которые постоянно изменяют и перерисовывают большие битовые поля, могут работать медленно, в сравнении с прорисовкой аппаратно-независимых образов с использованием вызовов GDI. Так как каждый объект или битовый образ являются локальными для клиентского приложения, они должны пересылаться в составе сообщения на сервер при всякой перерисовке экрана. Для обеспечения оптимальной производительности приложениям следует либо перерисовывать, по возможности, только измененные фрагменты битового образа, либо рисовать при помощи функций GDI, что позволяет реализовывать преимущества методов кэширования и пакетирования. Новый Win32 GDI API предоставляет более полный, чем GDI API 16-разрядной Windows, набор средств рисования, необходимый сложным приложениям.
