Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

OC Windows & OC Linux. Лабораторные работы по курсу «Операционные системы»

.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
Функция LockResource фиксирует данные в памяти и возвраща­ет дальний указатель на соответствующий буфер. После фиксирова­ния Windows не станет удалять сегмент с ресурсами из памяти, так что приложение сможет использовать данные в любой момент вре­мени.
После того как приложение использовало ресурс и он стал не нужен, следует расфиксировать память ресурса, вызвав UnlockResource. Функция определена через функцию GlobalUnlock следующим образом:
BOOL WINAPI GlobalUnlock(HGLOBAL hGlb);
#define UnlockResource (h) GlobalUnlock (h)
Эти, а также и другие функции управления памятью мы рас­смотрим позже, в отдельной главе, посвященной управлению памя­тью в операционной системе Windows.
Перед завершением работы приложения следует освободить по­лученный ресурс, вызвав функцию FreeResource:
BOOL WINAPI FreeResource(HGLOBAL hGlb);
В качестве параметра hGlb следует передать идентификатор ре­сурса,
полученный от функции LoadResource.
31
функцию
ЛАБОРАТОРНАЯ РАБОТА 3
УПРАВЛЕНИЕ ПАМЯТЬЮ
Введение
Защищенный режим работы процессора накладывает на прило­жения свои ограничения. Если программа, составленная для MS­DOS, имеет доступ к любому участку основной, расширенной или дополнительной памяти, а также к любому оборудованию компью­тера (через порты ввода/вывода), приложение Windows поставлено в жесткие рамки.
Например, приложение может
работать только с теми блоками памяти, которые ей принадлежат или получены от операционной системы. Приложение не может выполнять запись в сегмент кода и не может передавать управление в сегмент данных. Что же касается портов ввода/вывода, то в расширенном режиме работы приложе­ние, как правило, не имеет к ним непосредственного доступа
. Если приложение попытается вывести данные в порт, это приведет к пе­реключению задачи. Операционная система Windows проверит но­мер порта и, возможно, предоставит вам возможность что-нибудь в него записать.
Цель работы: ознакомить студентов с механизмом управления памятью в операционной системе Windows и функциями программ­ного интерфейса Windows, предназначенные для работы с оператив­ной памятью.
О
ПИСАНИЕ РАБОТЫ
Приложение Windows может делать все что угодно, если оно работает вместе с так называемым виртуальным драйвером или, как его еще называют, драйвером виртуального устройства ввода/ вы-
вода. Виртуальный драйверэто особая разновидность драйверов в Windows. Виртуальные драйверы предназначены для создания вир-
туальных устройств ввода/вывода, предоставляемых в пользование параллельно работающим приложениям Windows и
виртуальным
машинам MS-DOS. Так как виртуальные драйверы работают непо-
средственно с аппаратурой, для них не действует большинство огра­ничений, накладываемых на приложения Windows.
32
1.1. Особенности защищенного режима работы процессора
1.1.1. Адресация памяти в реальном режиме
Для адресации байта памяти в реальном режиме работы исполь­зуются две 16-разрядные компоненты адреса – сегмент и смещение. Физический адрес, который попадает на шину адреса системной платы компьютера, складывается (в буквальном смысле этого слова) из сдвинутой влево на четыре бита нулевыми битами сегментной компоненты и компоненты смещения. Перед сложением компонента смещения расширяется до 20 бит так, что в старшие четыре бита записываются нули.
Задавая произвольные значения для сегмента и смещения, мы можем сконструировать физический адрес для обращения к памяти размером 1 Мбайт плюс 64 Кбайт (и минус 16 байт).
Адрес, состоящий логическим адресом реального режима. Диапазон логических адре­сов от 0000h:0000h до FFFFh:OOOFh соответствует диапазону физи­ческих адресов от 00000h до FFFFFh. Этот диапазон адресов соот­ветствует первому мегабайту оперативной памяти.
Диапазон логических адресов от FFFFh:0010h до FFFFh:FFFFh соответствует так называемой области старшей памяти (High Mem­ory Area). Размер области старшей памяти равен 64 Кбайт байт, и эта память доступна в реальном режиме для процессора мо­дели 80286 и более старших моделей.
1.1.2. Адресация памяти в защищенном режиме
В защищенном режиме, как и в реальном, логический адрес со­стоит из двух компонент. Однако эти компоненты называются не сегмент и смещение, а селектор и смещение. Для ческого адреса в процессоре 80286 используются также две таблицы дескрипторов – глобальная таблица дескрипторов GDT (Global De­scriptor Table) и локальная таблица дескрипторов LDT.
В расширенном режиме работы Windows приложения могут пользоваться так называемой виртуальной памятью. Виртуальная память позволяет создать иллюзию работы с оперативной памятью огромного размера.
(Local Descriptor Table). Селектор используется для адресации ячейки одной из таблиц дескрипторов, информации базовый 24-разрядный адрес сегментов.
из сегмента и селектора, мы будем называть
и дополненной справа четырьмя
без 16
вычисления физи-
содержащей помимо прочей
33
Для получения физического адреса базовый адрес складывается со смещением, расширенным до 24 разрядов. Таким образом, не­смотря на то, что компоненты адреса остались, как и в реальном ре­жиме, 16-разрядными, новая схема адресации защищенного режима процессора 80286 позволяет адресовать до 16 Мбайт памяти, так как в результате преобразования получается 24-разрядный физический адрес.
Кроме индекса ной таблицы при формировании физического адреса, селектор со­держит еще два поля.
Поле TI (Table Indicator) используется для выбора таблицы де­скрипторов. Как мы уже говорили, существуют таблицы дескрипто­ров двух типов. В любой момент времени может использоваться од­на глобальная таблица дескрипторов и одна локальная таблица деск рипторов. Если бит TI равен 0, для выборки базового адреса исполь­зуется глобальная таблица дескрипторов GDT, если 1 – локальная
LDT.
Поле RPL (Requested Privilege Level) селектора содержит уро­вень привилегий, запрошенный программой при обращении к сег­менту. Программа может обращаться только к таким сегментам, ко­торые имеют соответствующий уровень привилегий. На этом осно­вана защита системных данных от или в результате программной ошибки) со стороны прикладных программ.
Таблица дескрипторов содержит, помимо базового адреса сег­мента, другую информацию, описывающую сегмент. При вычисле­нии физического адреса процессор следит за тем, чтобы физический адрес не выходил за пределы, указанные в дескрипторе сегмента. Программа не может обратиться к памяти, лежащей вне указанных в дескрипторе. Если же она попробует это сделать, ее ра­бота будет прервана. Поэтому, создав, например, сегмент для хране­ния массива размером 100 байт, вы не сможете записать в него 101 байт или 10 Кбайт данных.
Поле доступа содержит уровень привилегий сегмента и инфор­мацию о типе сегмента. Существуют сегменты кода, ных и системные сегменты. Кроме того, для сегмента кода можно запретить операцию чтения, а для сегмента данных – операцию за­писи. Поэтому операционная система может создать сегменты кода,
, используемого для выбора ячейки дескриптор-
разрушения (преднамеренного
пределов,
сегменты дан-
-
34
которые можно выполнять, но нельзя читать, и сегменты данных, защищенные от записи.
Что же касается привилегий, в процессорах 80ххх и Pentium существуют четыре уровня привилегий – от 0 до 3, причем наи­большие привилегии соответствуют уровню 0.
В кольце 0 обычно работает ядро операционной системы. Коль­цо 1 соответствует уровню привилегий драйверов, кольцо 2 – сис­темам, таким, как системы привилегированном кольце 3 располагаются прикладные програм­мы, запускаемые пользователем.
1.2. Работа с памятью в приложениях Windows
1.2.1. Получение глобального блока памяти
Для получения глобального блока памяти вы должны использо­вать функцию GlobalAlloc :
HGLOBAL WINAPI GlobalAlloc(UINT fuAlloc, DWORD cbAlloc);
Параметр fuAlloc определяет тип выделяемой памяти. Размер блока памяти в байтах должен передаваться через параметр cbAlloc, причем вы можете заказать блок памяти размером больше, чем 64 Кбайт. Для стандартного режима работы Windows можно зака­зать блок памяти размером до 1 Мбайт без 80 байт, для расширенно­го – до 16 Мбайт без 64 Кбайт.
Функция возвращает идентификатор глобального блока памяти или NULL, если Windows не может выделить память указанного объема.
Параметр fuAlloc должен быть указан как ция следующих значений:
управления базами данных. В наименее
логическая комбина-
Флаг Описание
GMEM_DDESHARE
Блок памяти будет использоваться со­вместно несколькими приложениями при помощи механизма динамическо­го обмена данными DDE
35
GMEM_DISCARDABLE Заказывается удаляемый блок памяти.
Этот флаг должен использоваться со­вместно с флагом GMEM MOVEABLE
GMEM_FIXED
GMEM_LOWER
GMEM_MOVEABLE
GMEM_NOCOMPACT
Заказывается фиксированный блок па­мяти. Этот флаг несовместим с флагом GMEMMOVEABLE. При работе в сре­де Windows версии 3.1 в защищенном режиме фиксированный сегмент, соз­данный с использованием флага GMEM _FIXED, является перемещаемым. Для такого сегмента в процессе перемеще­ния логический адрес не изменяется, но линейный (и, следовательно, физи­ческий) может изменяться
Синоним для GMEMNOTBANKED. He используется в Windows версии 3.1
Заказывается перемещаемый блок па­мяти. Логический адрес перемещаемо­го блока памяти может изменяться. Этот флаг несовместим с флагом
GMEM FIXED
Для удовлетворения запроса памяти не следует – выполнять объединение всех свободных участков памяти в один и удалять блоки памяти, отмеченные как удаляемые
GMEM_NODISCARD
Для удовлетворения запроса памяти не следует выполнять объединение всех свободных участков памяти в один
36
GMEM_NOTBANKED
Получить блок памяти вне фрейма до­полнительной памяти EMS. Не ис­пользуется в Windows версии 3.1
GMEM_NOTIFY
Если заказанный объект будет удален, требуется вызов процедуры извеще­ния. Процедура извещения назначает­ся функцией GlobalNotify и должна располагаться в фиксированном сег­менте кода в библиотеке DLL. С ее помощью приложение может разре­шить или запретить Windows удалять блок данных
GMEM_SHARE
GMEM_ZEROINIT
GHDN
Синоним для GMEM_DDESHARE
Во все байты блока необходимо запи­сать нулевые значения
Синоним для комбинации флагов
GMEM_MOVEABLE и GMEM_ZERO­INIT
GPTR
Синоним для комбинации флагов GMEM_FIXED и GMEM_ZEROINIT
Идентификатор, полученный от функции GlobalAlloc, нельзя использовать для адресации памяти непосредственно. Напомним, что пока вы не зафиксировали блок памяти, его логический адрес недоступен.
1.2.2. Фиксирование и расфиксирование блока памяти
Для получения доступа к полученному блоку памяти его необ­ходимо зафиксировать, вызвав функцию GlobalLock:
void FAR* WINAPI GlobalLock(HGLOBAL hglb);
Функция GlobalLock фиксирует блок памяти, идентификатор которого передается ей через параметр hglb и возвращает логиче­ский адрес зафиксированного блока или NULL, если указанный блок удален или произошла ошибка.
37
В защищенном режиме работы Windows продолжает переме­щать блоки памяти, зафиксированные функцией GlobalLock, изме­няя базовый адрес в локальной таблице дескрипторов. Даже для фиксированных блоков памяти вызов этой функции все же необхо­дим, потому что нужно получить логический адрес блока памяти.
Для каждого блока памяти Windows поддерживает счетчик фиксирований. Этот счетчик увеличивается при вызове
функции
GlobalLock и уменьшается при расфиксировании блока функцией GlobalUnlock:
BOOL WINAPI GlobalUnlock(HGLOBAL hglb);
Если содержимое счетчика уменьшилось до нуля, функция воз­вращает значение FALSE. В противном случае возвращается TRUE.
Файл windowsx.h содержит макрокоманды, облегчающие рабо­ту с глобальными блоками памяти. Например, макрокоманда Glo-
balAllocPtr получает блок памяти и фиксирует его:
#define GlobalAllocPtr(flags, cb) \
(GlobalLock(GlobalAlloc((flags), (cb))))
В данном случае идентификатор полученного блока памяти не сохраняется, так как он не нужен. Вы можете освободить
блок памя-
ти, зная только его логический адрес.
1.2.3. Определение идентификатора блока памяти по его адресу
С помощью функции GlobalHandle вы можете, зная селектор блока памяти, определить его идентификатор:
DWORD WINAPI GlobalHandle(UINT uGlobalSel);
Параметр uGlobalSel указывает селекторную компоненту логи­ческого адреса блока памяти.
Младшее слово возвращаемого значения содержит идентифика­тор блока памяти, старшее – селектор блока памяти. В случае ошиб­ки возвращается нулевое значение.
В файле windowsx.h определена макрокоманда GlobalPtrHandle, упрощающая получение идентификатора блока памяти по его логи­ческому адресу:
38
#define GlobalPtrHandle(lp) \
((HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lp))))
Макрокоманда SELECTOROF определена в файле windows.h и предназначена для получения селекторной компоненты логического адреса:
#define SELECTOROF(lp) HIWORD(lp)
В файле windows.h есть также определения для макрокоманды OFFSETOF, возвращающей компоненту смещения, и макрокоманда MAKELP, конструирующая указатель из компонент смещения и се- лектора:
#define OFFSETOF(lp) LOWORD(lp)
#define MAKELP(set, off) ((void FAR*)MAKELONG((off) ,
(sel)))
#define MAKELONG (low, high) ((LONG) (((WORD)(low)) |
\
(((DWORD) ((WORD)(high))) << 16)))
1.2.4. Работа с удаляемыми блоками памяти
Для того чтобы заказать удаляемый блок памяти, вы указать флаги GMEM_DISCARDABLE и GMEM_MOVEABLE, на­пример: hmemGlDiscard =
GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE, 20
00001);
При необходимости Windows может удалить полученный таким образом блок из памяти, сохранив только его идентификатор, и ис­пользовать ранее распределенную этому блоку память для других приложений.
При попытке зафиксировать удаленный блок с помощью функ­ции GlobalLock приложение получит от этой функции значение NULL. В этом случае значенную для определения состояния блока память, и проверить, находится ли данный блок в удаленном состоянии.
следует вызвать функцию GlobalFlags, предна-
должны
39
1.2.5. Изменение блока памяти
Если вам, например, надо изменить размер заказанного ранее блока памяти, сделав его равным 51200 байт, вы можете для этого использовать следующий фрагмент кода:
hmemGlobal = GlobalReAlloc(hmemGlobal, 51200, GMEM_MO­DIFY | GMEM_DISCARDABLE | GMEM_MOVEABLE | GMEM_ZE­ROINIT);
После вызова функции блок памяти будет перемещаемый и удаляемый, причем если раньше его размер был меньше 51200 байт, во все байты дополнительной памяти будут записаны чения.
1.2.6. Определение размера блока памяти
С помощью функции GlobalSize вы можете определить размер блока памяти по его идентификатору:
DWORD WINAPI GlobalSize(HGLOBAL hglb);
Эта функция возвращает размер блока памяти, идентификатор которого задан параметром hglb. Если указанный блок памяти не существует или удален, возвращается нулевое значение.
1.2.7. Дефрагментация памяти
Если вызвать функцию GlobalCompact, операционная система Windows выполнит
качестве параметра этой функции необходимо указать требуемый размер непрерывного блока свободной памяти:
DWORD WINAPI GlobalCompact(DWORD dwMinFree);
Функция возвращает размер самого большого доступного не­прерывного блока памяти, причем, если параметр не равен 0 или –1, выполняется дефрагментация памяти и удаление блоков, отмечен­ных как удаляемые. Если параметр функции указан как 0 или функция не выполняет дефрагментацию памяти, но возвращает пра­вильное значение с учетом возможного выполнения дефрагмента­ции.
1.2.8. Получение памяти в первом мегабайте адресного прост­ранства
Если у вас возникает необходимость заказать память, доступ­ную приложениям MS-DOS, и располагающуюся в первом мегабай-
объединение всех свободных блоков в один. В
нулевые зна-
–1,
40