The design of the UNIX Operating System 25 страница
Запрет прерываний
Наиболее простым решением поставленной задачи является следующая организация пролога и эпилога:
while (some condition) {
запретить все прерывания critical section
разрешить все прерывания remainder section
}
Поскольку выход процесса из состояния исполнение без его завершения осуществляется по прерыва-нию, внутри критической секции никто не может вмешаться в его работу. Однако такое решение может иметь далеко идущие последствия, поскольку позволяет процессу пользователя разрешать и запрещать прерывания во всей вычислительной системе. Допустим, что пользователь случайно или по злому умыс-лу запретил прерывания в системе и зациклил или завершил свой процесс. Без перезагрузки системы в такой ситуации не обойтись.
|
|
Тем не менее запрет и разрешение прерываний часто применяются как пролог и эпилог к критическим секциям внутри самой операционной системы, например при обновлении содержимого PCB.
|
|
Переменная-замок
В качестве следующей попытки решения задачи для пользовательских процессов рассмотрим другое предложение. Возьмем некоторую переменную, доступную всем процессам, с начальным значением рав-ным 0. Процесс может войти в критическую секцию только тогда, когда значение этой переменной-замка равно 0, одновременно изменяя ее значение на 1 – закрывая замок. При выходе из критической секции процесс сбрасывает ее значение в 0 – замок открывается (как в случае с покупкой хлеба студентами в разделе "Критическая секция").
|
|
shared int lock = 0;
/* shared означает, что */
/* переменная является разделяемой */
while (some condition) { while(lock); lock = 1;
critical section lock = 0;
Основы операционных систем | 54 |
|
|
remainder section
}
К сожалению, при внимательном рассмотрении мы видим , что такое решение не удовлетворяет условию взаимоисключения, так как действие while(lock); lock = 1; не является атомарным. Допустим, процесс P0 протестировал значение переменной lock и принял решение двигаться дальше. В этот момент, еще до присвоения переменной lock значения 1, планировщик передал управление процессу P1 . Он тоже изучает содержимое переменной lock и тоже принимает решение войти в критический участок. Мы получаем два процесса, одновременно выполняющих свои критические секции.
Строгое чередование
Попробуем решить задачу сначала для двух процессов. Очередной подход будет также использовать об-щую для них обоих переменную с начальным значением 0. Только теперь она будет играть не роль замка для критического участка, а явно указывать, кто может следующим войти в него. Для i-го процесса это выглядит так:
shared int turn = 0;
while (some condition) { while(turn != i);
critical section turn = 1-i;
remainder section
}
Очевидно, что взаимоисключение гарантируется, процессы входят в критическую секцию строго по оче-реди: P0, P1, P0 , P1, P0, ... Но наш алгоритм не удовлетворяет условию прогресса. Например, если значение turn равно 1, и процесс P0 готов войти в критический участок, он не может сделать этого, даже если про-
цесс P1 находится в remainder section.
Флаги готовности
Недостаток предыдущего алгоритма заключается в том, что процессы ничего не знают о состоянии друг друга в текущий момент времени. Давайте попробуем исправить эту ситуацию. Пусть два наших процес-са имеют разделяемый массив флагов готовности входа процессов в критический участок
shared int ready[2] = {0, 0};
Когда i -й процесс готов войти в критическую секцию, он присваивает элементу массива ready[i] значение равное 1. После выхода из критической секции он, естественно, сбрасывает это значение в 0. Процесс не входит в критическую секцию, если другой процесс уже готов к входу в критическую секцию или нахо-дится в ней.
Дата добавления: 2021-01-21; просмотров: 115; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!