Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОССО.doc
Скачиваний:
9
Добавлен:
20.09.2019
Размер:
937.98 Кб
Скачать

Вопрос 10. Операции над процессами и связанные с ними понятия

- Состязательная ситуация

- Критическая секция

Набор операций

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

  • создание процесса – завершение процесса ;

  • приостановка процесса (перевод из состояния исполнение в состояние готовность ) – запуск процесса (перевод из состояния готовность в состояние исполнение );

  • блокирование процесса (перевод из состояния исполнение в состояние ожидание ) – разблокирование процесса (перевод из состояния ожидание в состояние готовность ).

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

Операции создания и завершения процесса являются одноразовыми, так как применяются к процессу не более одного раза (некоторые системные процессы при работе вычислительной системы не завершаются никогда). Все остальные операции, связанные с изменением состояния процессов, будь то запуск или блокировка, как правило, являются многоразовыми. Рассмотрим подробнее, как операционная система выполняет операции над процессами.

Критическая секция — часть программы, в которой есть обращение к совместно используемым данным. При нахождении в критической секции двух (или более) процессов, возникает состояние «гонки» («состязания»). Для избежания данной ситуации необходимо выполнение четырех условий:

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

  2. В программе не должно быть предположений о скорости или количестве процессоров.

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

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

Вопрос 11. Взаимное исключение с активным ожиданием

- Запрет на прерывание

- Блокирующие переменные

- Строгое чередование

- Алгоритм Петерсона

- Команда TSL

Запрет на прерывания

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

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

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

Переменные блокировки

Теперь попробуем найти программное решение. Рассмотрим одну совместно используемую переменную блокировки, изначально равную 0. Если процесс хочет попасть в критическую область, он предварительно считывает значение переменной блокировки. Если переменная равна О, процесс изменяет ее на 1 и входит в критическую область. Если же переменная равна 1, то процесс ждет, пока ее значение сменится на 0. Таким образом, О означает, что ни одного процесса в критической области нет, а 1 свидетельствует, что какой-либо процесс уже находится в этом состоянии.

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

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

Строгое чередование

Третий метод реализации взаимного исключения иллюстрирован на рис. 2.6. Этот фрагмент программного кода, как и многие другие в данной книге, написан на С. Язык С был выбран, поскольку практически все существующие операционные системы написаны на С (или С++), а не на Java, Modula 3, Pascal и т. п. Язык С обладает всеми необходимыми свойствами для написания операционных систем: это мощный, эффективный и предсказуемый язык программирования. А язык Java, например, не является предсказуемым, поскольку у программы, написанной на нем, может в критический момент закончиться свободная память, и она вызовет сборщика мусора в исключительно неподходящее время. В случае С это невозможно, поскольку в С процедура сбора мусора в принципе отсутствует.

Алгоритм Петерсона

Датский математик Деккер (Т. Dekker) был первым, кто разработал программное решение проблемы взаимного исключения, не требующее строгого чередования. Подробное изложение алгоритма можно найти в [7].

В 1981 году Петерсон (G. L. Peterson) придумал существенно более простой алгоритм взаимного исключения. С этого момента вариант Деккера стал считаться устаревшим. Алгоритм Петерсона, представленный в листинге 2.1, состоит из двух процедур, написанных на ANSI С, что предполагает необходимость прототипов для всех определяемых и используемых функций. В целях экономии места мы не будем приводить прототипы для этого и последующих примеров.

Листинг 2.1. Решение Петерсона для взаимного исключения

#define FALSE О #define TRUE 1

idefine N 2 /* Количество процессов */

int turn: /* Чья сейчас очередь? */

int interested[N]; /* Все переменные изначально

/* равны О (FALSE) */

void enter region(int process): /* Процесс О или 1 */

int other; /* Номер второго процесса */

other = 1 - process: /* противоположный процесс */

interested[process] = TRUE: /* Индикатор интереса */

turn = process: /* Установка флага */

while (turn == process && interested[other] == TRUE) /* Пустой цикл */:

void leave region(int process) /* Процесс, покидающий

/* критическую область */

interestedCprocess] = FALSE: /* Индикатор выхода из

/* критической области */

Прежде чем обратиться к совместно используемым переменным (то есть перед тем, как войти в критическую область), процесс вызывает процедуру enter region

со своим номером (О или 1) в качестве аргумента. Поэтому процессу при необходимости придется подождать, прежде чем входить в критическую область. После выхода из критической области процесс вызывает процедуру leave region, чтобы обозначить свой выход и тем самым разрешить другому процессу вход в критическую область.

Рассмотрим работу алгоритма более подробно. Исходно оба процесса находятся вне критических областей. Процесс О вызывает enter region, задает элементы массива и устанавливает переменную turn равной 0. Поскольку процесс 1 не заинтересован в попадании в критическую область, происходит возврат из процедуры. Теперь, если процесс 1 вызовет enter region, ему придется подождать, пока interested [0] примет значение FALSE, а это произойдет только в тот момент, когда процесс О вызовет процедуру leave region при покидании критической области.

Представьте, что оба процесса вызвали enter region практически одновременно. Оба запомнят свои номера в turn. Но сохранится номер того процесса, который был вторым, а предыдущий номер будет утерян. Предположим, что вторым был процесс 1, отсюда значение turn равно 1. Когда оба процесса дойдут до конструкции while, процесс О войдет в критическую область, а процесс 1 останется в цикле и будет ждать, пока процесс О выйдет из нее.

Команда TSL

Рассмотрим решение, требующее участия аппаратного обеспечения. Многие компьютеры, особенно разработанные с расчетом на несколько процессоров, имеют команду Test and Set Lock (TSL) - проверить и заблокировать , которая действует следующим образом. В регистр считывается содержимое слова памяти, а затем в этой ячейке памяти сохраняется ненулевое значение. Гарантируется, что операция считывания слова и сохранения неделима - другой процесс не может обратиться к слову в памяти, пока команда не выполнена. Процессор, выполняющий команду tsl, блокирует шину памяти, препятствуя обращениям к памяти со стороны остальных процессоров.

Воспользуемся командой tsl. Пусть разделяемая переменная lock управляет доступом к общей памяти. Если значение lock равно О, любой процесс может изменить его на 1 и обратиться к общей памяти, а затем вернуть его обратно в О, пользуясь обычной командой типа move.

Как использовать команду tsl для реализации взаимного исключения? Решение приведено в листинге 2.2. Здесь представлена подпрограмма из четырех команд, написанная на некотором обобщенном (но типичном) ассемблере. Первая команда копирует старое значение lock в регистр и затем устанавливает значение переменной в 1. Потом старое значение сравнивается с нулем. Если оно ненулевое, значит, блокировка уже была произведена, и проверка начинается сначала. Рано или поздно значение окажется нулевым (это означает, что процесс, находившийся в критической области, покинул ее), и подпрограмма вернет управление в вызвавшую программу, установив блокировку. Сброс блокировки не представляет собой ничего сложного - просто помещается О в переменную lock. Специальной команды процессора не требуется.

Листинг 2.2. Вход и выход из критической области с помощью команды tsl

enter region:

tsl register.lock /* значение lock копируется в регистр */

/* значение переменной устанавливается равным 1 */

стр register.#0 /* Старое значение lock сравнивается с нулем */

jne enter region /* Если оно ненулевое, значит, блокировка уже была */ /* установлена, поэтому цикл */

ret /* Возврат в вызывающую программу */

/* процесс вошел в критическую область */

leave region:

move 1оск.#0 /* Сохранение О в переменной lock */

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