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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!