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

1233

.pdf
Скачиваний:
0
Добавлен:
15.11.2022
Размер:
625.43 Кб
Скачать

Синхронизация с помощью событий

Событие - это объект, который характеризуется одним свойством - фактом своего наступления. Событие может наступить, а может и не наступить. Наступление события характеризуется переводом его идентификатора в отмеченное состояние.

Любое событие, которое существует в системе, должно быть создано. Создание события выполняет функция:

HANDLE CreateEvent (LPSECURITY_ATTRIBUTES lpEventAttr, BOOL bManualReset,

BOOL bInitialState, LPCTSTR lpName);

Первый параметр содержит указатель на структуру с атрибутами системы защиты. Параметр bManualReset - флаг ручного сброса события. Значение True сообщает о том, что сброс может быть выполнен только с помощью функции ResetEvent, а значение False обеспечивает автоматический сброс события сразу после того, как задача завершит ожидание этого события; Третий параметр - флаг начального состояния: True - событие отмечено, False - не отмечено; Последний параметр может передавать указатель на символьную строку, содержащую имя события. Имя события задается, когда предполагается синхронизировать несколько самостоятельных процессов. Если предполагается использовать синхронизацию в рамках одного процесса, то lpName указывается NULL.

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

HANDLE OpenEvent (DWORD fdwAccess,

 

BOOL bInherit,

 

LPCTSTR lpName);

 

Первыми передаются флаги доступа, возможные значения которых

 

EVENT_ALL_ACCESS

- все флаги;

 

EVENT_MODIFY_STATE - позволяет переводить идентификатор в от-

меченное или неотмеченное состояние;

 

SYNCHRONIZEидентификатор можно использовать в файлах,

ожи-

дающих событий.

 

 

Второй параметр - флаг наследования: True - идентификатор

может

наследоваться потомком, False - идентификатор не может наследоваться потомком; Третий параметр - символьная строка с именем события.

Установка события (перевод в отмеченное состояние):

BOOL SetEvent (HANDLE hEvent);

Сброс события в неотмеченное состояние

BOOL ResetEvent (HANDLE hEvent);

Функция пульсирующей установки с последующим сбросом:

BOOL PulseEvent (HANDLE hEvent);

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

ВЗАИМОИСКЛЮЧЕНИЕ

Пример:

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

вобласти памяти strok.

Укаждой задачи есть копия кода

mov ax, strok inc

mov strok, ax

Пусть strok = 21678. Одна из задач начинает выполнять команды и после inc у нее кончается квант. Содержимое регистров сохраняется в блоке управления задачей. Управление передается следующей задаче и она успевает выполнить все команды. Значение strok становится 21679. В некоторый момент времени восстанавливается первая задача и выполняется последняя команда mov со значением

21679. А должно быть 21680.

Пример показывает, что совместное использование общего ресурса различными задачами (или процессами) при отсутствии согласованности может привести к ошибкам функционирования. Эту задачу решают путем взаимоисключения, т.е. путем предоставления каждому процессу монопольного исключительного права доступа к разделяемым данным. Взаимоисключение необходимо только в том случае, когда процессы обращаются к общим данным. Если они выполняют операции, не приводящие к конфликтным ситуациям, они должны работать параллельно. Когда процесс производит обращение к разделяемым данным, то говорят, что он находится на критическом участке. Таким образом, решение проблемы взаимоисключения в том, что если один процесс находится на своем критическом участке, необходимо исключить вхождение другого процесса на свой критический участке. Выполнение другого процесса продолжается, но без входа в критический участок. Если же это невозможно, процесс должен ожидать освобождения критических данных. Это одна из ключевых проблем параллельного программирования. Она решается программно, а в особо ответственных случаях аппаратно. Программирование критических участков требует особой тщательности (без зацикливаний и блокирования).

Требования к критическому участку:

1.В любой момент времени только один процесс может находиться внутри критического участка.

2.Ни один процесс не может оставаться внутри критического участка бесконечно долго.

3.Ни один процесс не должен ждать бесконечно долго входа в критический участок.

Для двух процессов задача решается алгоритмом Деккера. В этом алгоритме две задачи конкурируют за использование общего критического участка. Доступ к критическому участку предоставляется задачам попеременно:

program АлгоритмДеккера;

var ИзбранныйПроцесс: (первый, второй); Процесс1ХочетВойти, Процесс2ХочетВойти: boolean;

procedure Process1

21

begin

while true do begin

Процесс1ХочетВойти:= true; while Процесс2ХочетВойти do

if ИзбранныйПроцесс = второй then begin

Процесс1ХочетВойти:= false;

while ИзбранныйПроцесс= второй do; Процесс1ХочетВойти:= true;

end;

КритическийУчасток1; ИзбранныйПроцесс:= второй; Процесс1ХочетВойти:= false; ПрочиеОператоры1;

end;

end;

procedure Process2 begin

while true do begin

Процесс2ХочетВойти:= true; while Процесс1ХочетВойти do

if Избранный_Процесс = первый then begin

Процесс2ХочетВойти:= false;

while ИзбранныйПроцесс= первый do; Процесс2ХочетВойти:= true;

end;

КритическийУчасток2; ИзбранныйПроцесс:= первый; Процесс2ХочетВойти:= false; ПрочиеОператоры2;

end;

end;

end;

begin

Процесс1ХочетВойти:= false; Процесс2ХочетВойти:= false; Избранный_Процесс:= первый; parbegin

Process1;

Process2;

parend;

end.

Увеличение количества задач, требующих синхронизации, значительно усложняет алгоритм. Существуют варианты алгоритма для n процессов, которые разработал Дейкстра, например "алгоритм кондитера".

Критические секции в программном интерфейсе Windows

Синхронизация задач в рамках одного процесса осуществляется

с помощью объекта "критическая секция". Критическая секция создается как структура типа CRITICAL_SECTION в области глобальный переменных. Перед использованием критическая секция должна быть проинициализирована:

VOID InitializeCriticalSection (LPCRITICAL_SECTION lpCritSec);

Удаление критической секции после ее использования:

VOID DeleleCriticalSection (LPCRITICAL_SECTION lpCritSec);

После удаления доступ к критической секции невозможен. Критическая секция управляет доступом задач к фрагментам ко-

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

VOID EnterCriticalSection (LPCRITICAL_SECTION lpCritSec); VOID LeaveCriticalSection (LPCRITICAL_SECTION lpCritSec);

Для последовательного доступа к ресурсу из задач, созданных разными процессами, используется объект Mutex (Mutually Exclusive - взаимоисключающий). Данный объект, как и событие, может находится в отмеченном и в неотмеченном состоянии. Когда процесс становится владельцем объекта Mutex, он переводится в неотмеченное состояние, а все остальные процессы, которые обращаются за доступом к этому объекту, должны ожидать, пока он станет отмеченным.

Создание объекта Mutex:

HANDLE CreateMutex (LPSECURITY_ATTRIBUTES lpSecurityAttr, BOOL bInitialOwner,

LPCTSTR lpName);

Первый параметр передает указатель на структуру с атрибутами системы защиты (NULL - стандартные атрибуты). Второй параметр - флаг начального состояния: True - задача, создавшая Mutex, сразу же захватывает вход в критическую секцию, False - объект создан, но никому не принадлежит. Третий параметр содержит адрес строки с уникальным именем объекта. Другие процессы должны открыть объект Mutex с тем же самым именем:

HANDLE OpenMutex (DWORD fdwAccess, BOOL bInherit, LPCTSTR lpName);

Первый параметр - флаги доступа:

EVENT_ALL_ACCESS - все флаги доступа

SYNCHRONIZE - разрешить ожидание Mutex

Второй параметр - логический флаг, который разрешает или запрещает наследование идентификаторов. Третий параметр - указатель на символьную строку, которая содержит имя объекта.

Чтобы завладеть Mutex необходимо выполнить функцию

WaitForSingleObject (hMutex).

Освобождение объекта выполняется при завершении критической секции с помощью функции:

BOOL ReleaseMutex (HANDLE hMutex);

Полное уничтожение Mutex выполняется закрытием идентификато-

22

ра функцией CloseHandle.

Блокирующие функции

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

long InterLockedIncrement (LPLONG lpAddend); long InterLockedDecrement (LPLONG lpAddend); long InterLockedExchange (LPLONG lpTarget, long lNewValue);

СЕМАФОРЫ

Механизм взаимоисключения может быть реализован с помощью семафоров: двоичных и считающих. С семафором связаны инициализация и две операции: P(s) - закрытие, V(s) - открытие.

Двоичный семафор имеет два состояния - 0 и 1. Закрытый семафор находится в состоянии 0, открытый - в состоянии 1. При инициализации семафора определяется его начальное состояние:

ИнициализацияСемафора(s, 1);

или

ИнициализацияСемафора(s, 0);

Операция P(s): if s = 1

then s := 0 { закрыть семафор }

else блокировать обратившийся процесс по s; установить на выполнение готовый процесс;

Операция V(s):

if список процессов, ожидающих s, не пуст then деблокировать процесс, ожидающий S else s := 1; { открыть семафор }

Критический участок окаймляется операциями P(s) и V(s). Таким образом, двоичный семафор обеспечивает логику работы с собы-

тием (Event).

Считающие семафоры полезны при выделении одиночного ресурса из общего пула. При инициализации в s заносят количественный показатель объема ресурсов пула. P(s) вызывает уменьшение счетчика ресурса на единицу, а V(s)- увеличение счетчика на единицу, т.е.

операция P(s): if s > 0

then s := s - 1 else ожидать на s;

операция V(s):

if список процессов, ожидающих s не пуст then разрешить одному процессу работать else s := s + 1;

Считающие семафоры реализованы в программном интерфейсе Win-

dows. Их использование аналогично использованию событий и критических секций, т.е. семафор может быть в отмеченном или неотмеченном состоянии. Задача ожидает переключения семафора с помощью функции WaitForSingleObject, параметром которой является идентификатор семафора.

Когда семафор становится отмеченным, возобновляется работа задачи. Семафор является объектом, с помощью которого можно синхронизировать задачи, принадлежащие разным процессам: одна задача должна создать семафор, а все остальные - открыть. Функция создания семафора:

HANDLE CreateSemaphore (LPSECURITY_ATTRIBUTES lpSecurityAttr, long lInitialCount,

long lMaximumCount, LPCTSTR lpName);

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

Открытие семафора:

HANDLE OpenSemaphore (DWORD dwAccess, BOOL bInherit, LPCTSTR lpName);

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

SEMAPHORE_ALL_ACCESS - полный доступ

SEMAPHORE_MODIFY_STATE - разрешение изменения счетчика ресурсов SYNCHRONIZE - разрешено использование идентификатора в функциях ожидания.

Второй параметр содержит логический флаг разрешения/запрещения наследования идентификатора.

Увеличение счетчика ресурсов (освобождение) выполняется функцией:

BOOL ReleaseSemaphore(HANDLE hSemaphore, long lReleaseCount,

LPLONG lpPreviouseCount);

Первый параметр - идентификатор семафора; второй параметр - число единиц освобождаемого ресурса; третий параметр - адрес переменной, в которую будет записано предыдущее значение счетчика. Значение lReleaseCount должно быть больше нуля. Если освобождение ресурса состоялось, функция возвращает True. Отметим, что только эта функция позволяет определить количество ресурса семафора.

Уменьшение счетчика (выделение ресурса) выполняется функция-

ми WaitForSingleObject и WaitForMultipleObject.

Задачи, решаемые с помощью семафоров: 1. Взаимоисключение

Два процесса совместно используют общий ресурс. Программный код, на котором реализовано обращение к общему ресурсу, обозначен "критический_участок_1" для первого процесса и "критический_участок_2" для второго. Последовательность входа на критический участок несущественна.

program P1;

var Активный: семафор; procedure Process1; begin

23

while true do begin

....

P(Активный); критический_участок_1; V(Активный);

....

end

end;

procedure Process2; begin

while true do begin

....

P(Активный); критический_участок_2; V(Активный);

....

end

end; begin

ИнициализацияСемафора(Активный, 1); parbegin

Process1;

Process2 parend

end.

2. Синхронизация процессов Когда процесс выдает запрос на обмен данными с внешним уст-

ройством, он блокирует себя в ожидании завершения операции ввода/вывода. Заблокированный процесс должен быть активизирован ка- ким-либо другим процессом. Например, пусть одному процессу необходимо получить уведомление о наступлении некоторого события. Другой процесс может обнаружить, что данное событие произошло.

program P2;

var Событие: семафор; procedure Process1; begin

....

P(Событие);

....

end;

procedure Process2; begin

....

V(Событие);

....

end; begin

ИнициализацияСемафора(Событие, 1); parbegin

Process1;

Process2 parend

end.

3. "Производитель-потребитель"

Производитель генерирует информацию, потребитель - использует. Пусть они взаимодействуют при помощи одной разделяемой переменной BUFFER, то есть производитель вычисляет некоторое значение и помещает его по адресу переменной, а потребитель после этого считывает значение переменной BUFFER.

program P3;

var Доступ: семафор; ЧислоЗанесено: семафор;

BUFFER: integer;

procedure Process1; { производитель } var Результат: integer;

begin

while true do begin

вычисление Результата; Р(Доступ);

BUFFER := Результат; V(Доступ); V(ЧислоЗанесено) end

end;

procedure Process2; { потребитель } var Результат: integer;

begin

while true do begin

P(ЧислоЗанесено); P(Доступ); Результат := BUFFER; V(Доступ);

вывести Результат end

end; begin

ИнициализацияСемафора (Доступ, 1); ИнициализацияСемафора (ЧислоЗанесено, 0); parbegin

Process1;

Process2 parend

end.

ТУПИКИ

Оттяжки и проволочки - самая ужасная форма отказа К. Норткот Паркинсон

Говорят, что в мультипрограммной системе процесс находится в состоянии тупика (дедлока, клинча), если он ожидает события, ко-

торое

никогда

не произойдет.

"Зависание" системы - это ситуация,

когда

один

или более процессов оказываются в состоянии тупика.

Пример тупика

- транспортная пробка:

 

¦ ¦ ¦

¦

¦

----+ ¦ +-----------+

+---

24

 

¦<--------------------

 

----+ ¦ +-----------

+ - +---

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

¦ ¦ ¦

----+ V +-----------

+ ¦ +---

---------------------

 

----+

+-----------

+ ¦ +---

¦

¦

¦ ¦ ¦

Другой пример. В операционных системах тупики в большинстве случаев возникают в результате обычной конкуренции за обладание выделяемыми или закрепляемыми ресурсами (т.е. ресурсами, которые в каждый момент времени отводятся только одному пользователю и которые поэтому иногда называются ресурсами последовательного использования). Пусть Процесс1 удерживает Ресурс1 и ожидает освобождения Ресурса2. Процесс2 удерживает Ресурс2 и ожидает освобождения Ресурса1. Каждый процесс ждет, чтобы другой процесс освободил нужный ему ресурс, причем каждый не освобождает свой ресурс до тех пор, пока другой не освободит свой ресурс и т.д. Такое состояние кругового ожидания характерно для систем в тупиковом состоянии.

Возможны тупики и в системе спулинга (ввода/вывода с буферизацией). Режим спулинга применяется для повышения производительности системы путем изолирования программ от такого низкоскоростного периферийного оборудования как принтеры. Если, например, программе, выдающей строки данных на принтер, приходится ждать распечатки каждой строки, то такая программа будет выполняться медленно. Чтобы повысить скорость выполнения программы, строки данных, предназначенные для печати, записываются на более высокоскоростное устройство, например дисковый накопитель. В некоторых системах спулинга программа должна сформировать все выходные данные - только после этого начнется реальная распечатка. Система может оказаться в тупике, если дисковый буфер окажется целиком заполненным до завершения задания. Конечно, современные системы являются в этом смысле гораздо более совершенными. Они могут начинать печать до того, как завершится очередное задание, с тем чтобы полный или почти полный дисковый буфер опустошался уже в процессе выполнения задачи: сброс этого буфера на принтер можно поручить специальному системному процессу, независящему от потока пользовательских процессов и задач.

К тупикам приводит бесконечное откладывание низкоприоритетных процессов при поступлении в очередь все новых и новых заданий (проблема решается "старением" процесса, т.е. повышением приоритета с течением времени). В системах реального времени не должно быть тупиков, т.к. это может привести к катастрофическим последствиям.

Условия возникновения тупика

Можно сформулировать четыре необходимых условия тупика:

1. Условие взаимоисключения: процессы требуют предоставления им права монопольного управления ресурсами, которые им выделяются.

2.Условие ожидания ресурсов: процессы удерживают ресурсы, уже выделенные им, ожидая выделения дополнительных ресурсов.

3.Условие неперераспределяемости: ресурсы нельзя отобрать у процессов, удерживающих их, пока эти ресурсы не будут использованы для завершения работы.

4.Условие кругового ожидания: существует кольцевая цепь процессов, удерживающих ресурсы, требующиеся следующему процессу цепи.

Направления исследований по проблеме тупиков

В исследованиях по проблеме тупиков можно выделить следующие основные направления:

1.Предотвращение тупиков.

2.Обход тупиков.

3.Обнаружение тупиков

4.Восстановление после тупиков.

Предотвращение тупиков

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

Предлагается стратегия, включающая три принципа:

-каждый процесс должен запрашивать все требуемые ресурсы сразу и не начинаться, пока они не будут выделены;

-если процесс требует дополнительных ресурсов и получает отказ, он должен освободить все ресурсы и запросить потом всю совокупность ресурсов;

-введение линейной упорядоченности по типам ресурсов.

Все элементы этой стратегии имеют свои недостатки.

Обход тупиков

Используются алгоритмы, позволяющие обойти опасные участки при распределении ресурсов. Дейкстра предложил алгоритм рационального распределения ресурсов. Поскольку данный алгоритм имитирует действия банкира, который, располагая определенным источником капитала, выдает ссуды и принимает платежи, он получил название "алгоритма банкира".

Обнаружение тупиков

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

25

ния, а можно положиться на оператора компьютера.

Восстановление после тупика

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

В будущих системах тупики станут в большей степени критическим фактором, т.к.

1)системы будут ориентированы на асинхронную параллельную

работу;

2)будет реализовано преимущественно динамическое распределение ресурсов. Это может привести к тому, что в какой-то момент ресурсов может оказаться недостаточно;

3)увеличение количества ресурсов за счет включения в список ресурсов данных.

Пример тупика

Два процесса Пр1 и Пр2 разделяют два вида ресурсов р1 и р2, обращение к которым синхронизируется с помощью семафоров S1 и S2. Соответствующие операции расставляются следующим образом:

 

Пр1

 

Пр2

 

...

 

...

1

P(S1)

5

P(S2)

 

...

 

...

2

P(S2)

6

P(S1)

 

...

 

...

3

V(S1)

7

V(S1)

 

...

 

...

4

V(S2)

8

V(S2)

 

...

 

...

Пр2¦

 

¦

¦

¦

¦

A

 

¦ |---------------------------------------

 

 

 

 

 

 

 

¦ |

 

¦

¦

¦

¦

| B

+--

8+-|------

 

+--------

+--------

+--------

+-------

|----

¦

¦ |

 

¦

¦\\\\\\\\¦\\\\\\\\¦

|

¦

¦ |

 

¦

¦\\\\\\\\¦\\\\\\\\¦

|

¦ +7+-|------

 

+--------

+--------

+--------

+-------

|----

¦ p1¦ |

 

¦////////¦XXXXXXXX¦\\\\\\\\¦

|

¦ ¦ ¦ |

 

¦////////¦XXXXXXXX¦\\\\\\\\¦

|

¦ +6+-|--

C---

+--Y|---

Z+--------

+--------

+---

|---|----

p2

¦ |

|--------

|

¦\\\\\\\\¦\\\\\\\\¦

|

¦

¦ | |

¦

¦\\\\\\\\¦\\\\\\\\¦

|

+--5+-|-|----

+--------

+----

|X---------------

 

|--------

 

¦ | | -----------------

 

 

| ¦

¦

 

 

¦ | | |

¦

¦

¦

¦

 

---------------------------------------------------

1

 

2

3

4

Пр1

+--

p1----

+--------

+

¦

 

+--------p2-------+

Возможны три траектории выполнения процессов: Траектория А - без проблем.

Траектория В - в точке Х Пр2 ждет освобождения р2. Траектория С - дедлок в точке Z (Пр2 ждет р1, Пр1 ждет р2).

Средства обеспечения мультизадачности

в защищенном режиме работы процессора Intel

Вам уже известно, что каждое приложение может состоять из нескольких параллельно или последовательно работающих задач. Квантование времени процессора выполняется на уровне задачи. По прерыванию таймера процессор переключается от одной задачи к другой, за счет чего и реализуется мультипрограммный режим работы. Для хранения контекста неактивной в настоящий момент задачи используется сегмент состояния задачи TSS (Task State Segment), который адресуется при помощи двухбайтового регистра ТR (Task Register). Регистр содержит селектор дескриптора TSS в глобальной дескрипторной таблице.

Поле TYPE байта доступа дескриптора содержит значения 0х09 для неактивной задачи ("доступный" TSS) и 0х0A - для активной ("недоступный" TSS), то есть различаются значением бита 1 (отсчет от нуля). Переключение задачи в активное состояние осуществляется установкой этого бита.

Операционная система для каждой задачи создает свой TSS. Перед тем, как переключиться на выполнение следующей задачи, процессор сохраняет контекст текущей задачи в ее сегменте TSS. Контекст - это, прежде всего, состояние регистров. В сегмент сбрасываются:

регистры общего назначения EAX, EBX, ECX и EDX;

регистры-указатели ESP, EBP, ESI, EDI, EIP;

сегментные регистры ES, CS, SS, DS, FS, GS; регистр флагов EFLAGS;

регистр LDTR с селектором дескриптора в GDT локальной дескрипторной таблицы, распределенной данной задаче;

регистр базового адреса каталога страниц CR3. Таким образом, каждая задача может иметь свой собственный каталог таблиц стра-

ниц, что

позволяет выполнить изоляцию задач не только на уровне

сегментов, но и на уровне страниц.

 

+---------------------------------------

 

 

 

+

¦База карты ввода-

¦

0

¦ Т ¦

¦вывода

¦

 

¦ ¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

LDTR

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

GS

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

FS

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

DS

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

SS

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

CS

¦

+-------------------

 

+-------------------

 

¦

¦

0

¦

ES

¦

+---------------------------------------

 

 

 

¦

26

¦

 

EDI

 

¦

+---------------------------------------

 

 

 

¦

¦

 

ESI

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EBP

 

¦

+---------------------------------------

 

 

 

¦

¦

 

ESP

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EBX

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EDX

 

¦

+---------------------------------------

 

 

 

¦

¦

 

ECX

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EAX

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EFLAGS

 

¦

+---------------------------------------

 

 

 

¦

¦

 

EIP

 

¦

+---------------------------------------

 

 

 

¦

¦

 

CR3

 

¦

+---------------------------------------

 

 

 

¦

¦

0

¦

SS2

¦

+---------------------------------------

 

 

 

¦

¦

 

ESP2

 

¦

+---------------------------------------

 

 

 

¦

¦

0

¦

SS1

¦

+---------------------------------------

 

 

 

¦

¦

 

ESP1

 

¦

+---------------------------------------

 

 

 

¦

¦

0

¦

SS0

¦

+---------------------------------------

 

 

 

¦

¦

 

ESP0

 

¦

+---------------------------------------

 

 

 

¦

¦

0

¦

LINK

¦

+---------------------------------------

 

 

 

+

LINK предназначено для ссылки на TSS вызвавшей задачи при вложенном вызове задач. Здесь хранится селектор TSS, записанный командой CALL.

TSS содержит указатели на стеки для 0, 1 и 2-го приоритетных колец, соответственно SS0:ESP0, SS1:ESP1 и SS2:ESP2. Эти поля используются при межсегментных вызовах через вентили. Для каждого кольца защиты процессор назначает отдельные стеки. Когда задача вызывает функцию из другого кольца через вентиль вызова, процессор загружает указатель стека SS:ESP адресом нового стека, взятого из соответствующего поля TSS. В новый стек копируется адрес вершины старого стека, параметры функции, количество которых задано в вентиле вызова и адрес возврата. Таким образом, при вызове привилегированного модуля через вентиль вызова менее привилегированная программа не может передать в стеке больше параметров, чем это определено операционной системой для этого модуля. Включение адресов стеков в TSS позволяет разделить стеки задач и обеспечивает их автоматическое переключение при переключении задач.

При отладке программы устанавливается в 1 бит Т, в результате чего при переключении на задачу возникает отладочное исключение (0х01), которое может быть использовано отладчиком.

База карты ввода-вывода указывает 16-тиразрядное смещение начала битовой карты ввода-вывода (БКВВ) относительно TSS. Битовая карта ввода-вывода определяет порты, которые может использовать задача. Если задача обратится к несанкционированному порту ввода-вывода, произойдет исключение. Это необходимо для безопасной работы системы. Предел TSS должен определяться с учетом карты ввода-вывода. Каждый бит в карте соответствует адресу байта порта ввода-вывода. БКВВ завершается байтом 0хFF. При выполнении операций с портами процессор проверяет все биты, соответствующие адресу порта. Если какой-либо бит установлен в 1, генерируется исключение. Проверка битовой карта не выполняется, если флаг IOPL больше или равен уровню привилегий. Установка базы карты ввода-вывода большей или равной пределу TSS позволяет полностью запретить обращение к портам. Любая команда ввода-вывода приведет к генерации исключения.

Переключение задач

Переключение возможно по командам JMP, CALL и по прерыванию. В первом и втором случаях операндом является адрес TSS вызываемой задачи. Если переключение производится по команде JMP, то для возврата к выполнению первой задачи необходимо вновь использовать JMP с адресом ее TSS к качестве операнда. Команда CALL позволяет организовать вызов вложенных задач. Обратное переключение задач происходит по команде IRET. Адрес TSS для возврата команда IRET берет из поля LINK текущего сегмента TSS. При переключении командой CALL в поле EFLAGS сегмента TSS вызванной задачи устанавливается в 1 бит вложенной задачи NT. Команда JMP, если она использована для переключения задачи, сбрасывает бит NT. Вентили задач, вызываемых по команде CALL, располагаются в GDT или LDT.

Переключение по прерыванию обеспечивается размещением вентиля задачи в IDT.

ОБРАБОТКА ПРЕРЫВАНИЙ

Обычно случается не то, на что мы рассчитываем, а то, чего мы меньше всего ожидаем

(Б. Дизраэли) Прерывание - это событие, при котором меняется нормальная последовательность команд, выполняемых процессором. Выполняемый процесс приостанавливается и управление передается программе об-

работки прерывания. Точнее так:

-процесс переводится в состояние блокировки;

-управление передается операционной системе;

-ОС запоминает состояние процесса в PCB;

-ОС анализирует тип прерывания и передает управление соответствующей программе обработки этого прерывания.

Типы прерываний

1. SVC-прерывания (супервизорные прерывания), обращение к операционной системе. Инициатор - работающий процесс, выполняющий

27

команду SVC, т.е. осуществляющий запрос на предоставление конкретной системной услуги - выполнения операции ввода-вывода, изменения размера памяти и т.п.

2.Прерывания ввода-вывода - инициируются аппаратурой вво- да-вывода. Сигнализируют об изменении состояния устройств вво- да-вывода.

3.Внешние прерывания - истечение кванта времени, сигнал прерывания от другого процессора.

4.Прерывания по рестарту - перезагрузка ОС.

5.Прерывания по контролю (ошибке) программы - вызываются ошибками, обнаруженными при выполнении процесса: деление на нуль, попытка выполнения привилегированной команды и т.д.

6.Прерывания по контролю (ошибке) машины - аппаратные ошиб-

ки.

Для каждого типа прерываний предусмотрены обработчики преры-

ваний. (IH - Interrupt Handler).

При обработке прерываний используются слова состояния программы (Process Status Word - PSW), которые управляют порядком выполнения команд и содержат информацию о состоянии процесса. Существуют:

- текущее PSW; - новое PSW; - старое PSW.

В текущем PSW содержится адрес следующей команды, подлежащей выполнению. Кроме того в нем указаны типы разрешенных и запрещенных прерываний (на данный момент). Центральный процессор реагирует только на разрешенные прерывания, однако ему нельзя запретить реагировать на прерывания типов 1, 4, 5. Для каждого типа прерываний создается новое PSW с адресом IH. При прерывании аппаратно происходит переключение PSW:

- текущее PSW становится старым PSW для прерываний этого ти-

па;

- новое PSW для прерываний этого типа становится текущим

PSW.

После завершения работы IH старое PSW для прерываний этого типа становится текущим PSW и прерванный процесс продолжается.

ОБРАБОТКА ПРЕРЫВАНИЙ В ЗАЩИЩЕННОМ РЕЖИМЕ

В защищенном режиме все прерывания делятся на 2 типа - обычные и исключения. Обычное прерывание инициализируется инструкцией INT или внешним событием. Перед передачей управления программе обслуживания прерывания флаг IF сбрасывается и прерывания запрещаются.

Исключение происходит в результате ошибки при выполнении команды, например, попытки записи за пределы сегмента, использование селектора, не определенного в таблице и т.п. Исключения соответствуют зарезервированным для процессора внутренним прерываниям реального режима. При передаче управления обработчику исключения флаг IF не меняется, поэтому особые случаи, возникающие в задачах не оказывают влияния на выполнение других задач.

Таблица прерываний IDT

Дескрипторная таблица прерываний (IDT) содержит вентили прерываний, исключений и задач. Расположение IDT определяется содер-

жимым внутреннего регистра IDTR, структура которого аналогична GDTR, IDTR обычно загружают перед входом в защищенный режим.

Формат дескриптора IDT:

 

 

 

 

+----------------------------------------------------+

 

¦старшее слово¦досту簾¦¦¦¦¦¦¦селектор ¦младшее слово¦

 

¦смещения

¦

¦¦¦¦¦¦¦¦¦

¦смещения

¦

 

+----------------------------------------------------+

 

16

 

8

8

16

16

 

 

Поле TYPE байта доступа содержит значения:

 

 

0xЕ - вентиль прерывания,

 

 

 

 

0xF - вентиль ловушки,

 

 

 

 

 

0x5 - вентиль задачи.

 

 

 

 

 

Селектор показывает расположение дескриптора вентиля в

GDT.

Обычно это кодовый сегмент.

 

 

 

 

 

Для обработки

исключений

зарезервированы первые 0x20 деск-

рипторов IDT. Список исключений:

 

 

 

 

0x00

- ошибка при выполнении деления

 

 

0x01

- исключение для пошаговой работы

 

 

0x02

- немаскируемое прерывание

 

 

 

0x03

- исключение по точке останова (Breakpoint)

 

0x04

- переполнение

 

 

 

 

0x05

- превышение заданного диапазона

 

 

0x06

- недействительный код операции, или длина коман-

 

 

ды больше 10 байт

 

 

 

0x07

- отсутствие сопроцессора

 

 

 

0x08

- двойная ошибка

 

 

 

 

0x09

- превышение сегмента сопроцессором

 

 

0x0A

- недействительный сегмент TSS

 

 

0x0B

- отсутствие сегмента в памяти

 

 

0x0C

- исключение при работе со стеком (отсутствие

 

 

сегмента стека в памяти или переполнение стека)

0x0D

- защита памяти (попытки доступа к сегментам

па-

 

 

мяти при недостаточном уровне привилегий)

 

0x0E

- отказ страницы памяти

 

 

 

0x0F

- зарезервировано

 

 

 

0x10

- исключение сопроцессора

 

 

 

0x11..0x1A - зарезервированы

Для ряда исключений (0x08, 0x0A, 0X0B, 0X0C и 0X0D) в стек помещается код ошибки, содержащей информацию о природе исключения.

Кроме того, большинство зарезервированных прерываний обладают свойством повторной запускаемости, т.е. помещения в стек адреса команды вызывающей исключение, а не следующей, как в реальном режиме. В результате после обработки исключения повторяется прерванная команда. Например, если произошло обращение к сегменту, отсутствующему в памяти, то генерируется исключение 0x0B, обработчик которого выполняет свопинг, после чего повторяется команда обращения по адресу.

Если при обработке исключения возникает еще одно исключение, то генерируется исключение "двойная ошибка"(0x08). Возникновение третьего исключения при обработке этого приводит к тому, что процессор перезапускается.

Обработка аппаратных прерываний

28

Так как номера 0x08..0x0F зарезервированы для обработки исключений, то необходимо перепрограммировать контроллер прерываний. Например, прерывание, генерируемое по сигналу IRQ0, обрабатывать 0x20 дескриптором IDT, по сигналу IRQ1 - 0x21 и т.д. Функция перепрограммирования контроллера прерываний приведена в книге Фроловых "Защищенный режим работы процессоров Intel 80286/80386/80486" на стр. 63-64.

Управление потоками заданий. Планирование заданий и загрузка процессоров

Не рассказывайте о том, как много и усердно вы работаете. Скажите лучше, что вам удалось сделать.

Джеймс Дж. Линг

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

1)верхний уровень определяется совокупностью заданий, которым будет разрешено активно конкурировать за захват ресурсов. Этот вид планирования называют планированием допуска, поскольку тут определяется, какие задания будут допущены в систему. Вошедшие в это множество задания становятся процессами;

2)промежуточный уровень определяется множеством процессов, которым будет разрешено состязаться за захват ЦП. Формирование этого списка осуществляется за счет механизмов приостановки/возобновления. Планировщик промежуточного уровня отслеживает текущие колебания системной нагрузки, приостанавливая и вновь активизируя процессы, что обеспечивает равномерную работу всей системы

испособствует достижению желаемых скоростных характеристик. Алгоритмы планировщика этого уровня должны своевременно оценивать складывающуюся ситуацию;

3)нижний уровень обеспечивает выбор одного процесса (задачи), которому будет представлен ЦП. Планирование на нижнем уровне называется диспетчеризацией. Планировщик нижнего уровня (диспетчер задач) наиболее критичен к времени выполнения, поскольку он включается по завершении каждого кванта времени, предоставляемого пользовательскому процессу.

Цели планирования Планирование заданий обычно осуществляется в соответствии с

некоторой дисциплиной. Выбранная дисциплина планирования должна обеспечивать выполнение следующей совокупности целей:

1)быть справедливой. Дисциплина считается справедливой, если ко всем процессам она относится одинаково и ни один процесс не будет отложен на бесконечное время;

2)обеспечивать максимальную пропускную способность системы. Количество заданий, обслуженных за единицу времени должно быть возможно максимальным;

3)обеспечивать минимальное время ответа (для интерактивных

систем);

4)быть предсказуемой, т.е. одно и то же задание должно выполняться в разных сеансах приблизительно за одно и то же время;

5)минимизировать накладные расходы (расходы ресурсов на организацию вычислительного процесса). Данное требование оспаривается рядом специалистов, поскольку даже достаточно высокий уровень накладных расходов вполне может обеспечивать стабильную эффективность использования системы;

6)сбалансировать использование ресурсов. Механизмы планирования ресурсов должны стремиться к повышению коэффициента использования системных ресурсов. Предпочтение должно оказываться тем процессами, которые будут занимать недогруженные ресурсы;

7)обеспечивать баланс между временем ответа и коэффициентом использования ресурсов (для интерактивных систем). Баланс обеспечивается за счет некоторой недогрузки ресурсов, что позволит их сразу же использовать для выравнивания времени реакции на запрос пользователя;

8)исключать бесконечное откладывание. При наличии большого потока заданий необходимо обеспечить выталкивание этих процессов. Это возможно при учете старения процесса - чем дольше процесс ожидает некоторый ресурс, тем выше приоритет ему назначается;

9)учитывать приоритеты;

10)оказывать предпочтение процессам, занимающим ключевые ресурсы. Оценка ключевого ресурса, т.е. такого, который может оказать принципиальное влияние на общую производительность системы, должна осуществляться планировщиком нижнего уровня;

11)создавать лучшие условия для процессов с примерным поведением (предсказуемо и стабильно). Например, лучшие условия работы должны создаваться для процессов, требующих менее частой подкачки страниц;

12)характеризоваться постепенностью снижения работоспособности при увеличении нагрузок. Механизм планирования не должен сразу же терять работоспособность под тяжестью большой системной нагрузки. Планирование всех уровней ориентировано на защиту действующей части системы от превышения нагрузки. Уровень обслуживания процессов может постепенно снижаться, но ни в коем случае не должен завершаться катастрофой.

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

Критерии планирования

1.Фактор, лимитирующий процесс, ограничивает производительность системы: прежде всего, это ввод/вывод, т.е. на быстродействие влияют стадии обмена процесса с внешними устройствами. Лимитирующим фактором может быть ЦП - для процессов, которые полностью используют выделенный квант времени (задачи вычислительного характера). Производительность системы в данном случае зависит от размера кванта, от текущего приоритета и нагрузки.

2.Характер процесса позволяет определить главные цели дисциплины планирования по отношению к этому процессу. Процесс может быть пакетным или диалоговым. Пакетный выполняется от начала до конца без обмена (преимущественно) с пользователем, а диалоговый требует постоянного обмена информацией с пользователем.

3.Рабочие характеристики процесса:

-приоритетность;

-наличие прерывания по отсутствии страниц;

-время ЦП, уже выделенному процессу;

-ожидаемое время завершения.

29

Механизм планирования должен как можно раньше определять характер заданий. Механизм планирования должен отдавать предпочтение коротким заданиям, лимитируемым вводом/выводом.

Дисциплины планирования

1.По сроку завершения. задание должно быть завершено не позднее указанного для него срока. Результаты таких заданий могут иметь значение, если они были получены вовремя. Системы реально времени работают именно по такой дисциплине. Наличие в системе нескольких процессов, требующих завершения к близким срокам, может в значительной степени осложнить работу планировщика, либо потребовать включения специальных методов оптимизации, гарантирующих соблюдения всех сроков. Стоимость выполнения подобных заданий существенно выше стоимости прохождения ординарных процессов.

2.Более простой является дисциплина планирования по принципу FIFO. Это планирование обеспечивает хорошую справедливость, однако многие цели планирования оказываются не выполненными. Например, время ответа в режиме разделения времени гарантируется слабо.

3.Циклическое планирование, когда задания обслуживаются по кругу (Round Robin, RR). Грубо говоря, это FIFO с ограниченным временем кванта ЦП. Если процесс не завершается по истечении кванта, он возвращается в конец очереди готовых процессов. При работе в режиме разделения времени обеспечивается хорошее время ответа для всех интерактивных пользователей.

4.

Дисциплина SJF (Shortest Job First) - кратчайшее задание

- первым. Эта дисциплина

обеспечивает уменьшение минимального

времени ожидания, по сравнению с FIFO, но дисперсия времен ожида-

ния оказывается несколько

выше. Проблема возникает при оценке

времени выполнения того или

процесса. Регулярный счет однотипных

заданий позволяет применять

данную дисциплину.

5.Планирование по принципу SRT (Shortest Remaining Time) -

по наименьшему отстающему времени. Данный механизм учитывает, сколько время осталось процессу до завершения.

6.По относительно наибольшему времени реакции HRN (Highest Response Ratio Next). Эта дисциплина обеспечивает выполнение задания с приоритетом, учитывающим не только время обслуживания процесса, но и время, затраченное на ожидание. Динамический приоритет рассчитывается по формуле:

Приоритет = (Время_ожидания + Время_обслуживания) /

Время_обслуживания

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

Многоуровневые очереди с обратными связями

Механизм планирования должен:

-оказывать предпочтение коротким заданиям;

-оказывать предпочтение заданиям, лимитируемым вводом-вы- водом, чтобы обеспечить хороший коэффициент использования внешних устройств;

-как можно быстрее определить характер задания и начать планирование выполнения этого задания.

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

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

ро обслуживаются,

если они являются либо интерактивными,

либо

лимитируемыми вводом-выводом. Процессы,

лимитируемые ЦП,

пол-

ностью используют квант времени, а затем

переходят в конец оче-

реди следующего,

более низкого приоритета

уровня. Чем

дольше

процесс занимает

ЦП, тем ниже становится его приоритет,

пока

процесс не опускается в очередь самого низкого приоритета, которая реализует принцип RR, где он и завершается. Размер кванта обычно увеличивается по мере перехода процесса в каждую следующую очередь.

 

+---

+ +---

+

+---

+

+-----------

+

1 ур.

¦

+-¦

+ ...

¦

+----¦Использ. ЦП+----- завершение

FIFO

+---

+ +---

+

+---

+

+-----------

+

+-------

 

переключение---------------

 

+

 

¦

+---

+ +---

+

+---

+

+-----------

+

2 ур.+-¦

+-¦

+ ...

¦

+----¦Использ. ЦП+----- завершение

FIFO

+---

+ +---

+

+---

+

+-----------

+

+-------

 

переключение---------------

 

+

 

¦

+---

+ +---

+

+---

+

+-----------

+

3 ур.+-¦

+-¦

+ ...

¦

+----¦Использ. ЦП+----- завершение

FIFO

+---

+ +---

+

+---

+

+-----------

+

+-------переключение---

.....

-------+

 

+-+---

+ +---

+

+---

+

+-----------

+

RR

¦

+-¦

+ ...

¦

+----¦Использ. ЦП+----- завершение

+-+---

+ +---

+

+---

+

+-----------

+

+-------

 

переключение---------------

 

+

 

Таким образом, чем дольше процесс находится в системе, тем больше времени ЦП ему выделяется. Однако частота получения ЦП снижается, поскольку процессы, обслуживаемые на верхних уровнях, имеют более высокие приоритеты.

Сеть многоуровневых очередей - это пример адаптивного механизма планирования. Он позволяет разделять процессы на категории в соответствии с их потребностями во времени ЦП. В системе с разделением времени каждый раз, когда процесс выходит из системы, он может быть помечен признаком очереди самого низкого уровня, в которой он побывал. Когда этот процесс впоследствии вновь войдет в сеть очередей, он будет направлен прямо в ту очередь, в которой он последний раз завершал свою работу. То есть планировщик оценивает перспективу поведения процесса по его поведению в недавнем прошлом. Поэтому процесс, лимитируемый ЦП, при возвращении в сеть очередей не будет помещаться в очереди более высоких уровней, где он только мешал бы обслуживать короткие процессы высокого приоритета или процессы, лимитируемые вводом-выво- дом.

Однако, если процессы всегда помещать на самый низкий уровень, который они занимали прошлый раз, то система не сможет реагировать на изменения характера процесса, например на то, что процесс, бывший по преимуществу вычислительным, становится "обменным" (это вполне соответствует реальной картине: большинство задач решается по схеме "ввод данных - вычисление - вывод результатов"). Эту проблему можно решить, если в блоке управления процессом указывать долю использования кванта времени ЦП. Неполное использование кванта времени дает основания для перемещения процесса на один уровень вверх по сети очередей.

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]