The design of the UNIX Operating System 30 страница



 

}

 

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

 

Мониторы

 

Хотя решение задачи producer-consumer с помощью семафоров выглядит достаточно изящно, програм-мирование с их использованием требует повышенной осторожности и внимания, чем отчасти напоминает программирование на языке Ассемблера. Допустим, что в рассмотренном примере мы случайно поменя-ли местами операции P, сначала выполнив операцию для семафора mutex, а уже затем для семафоров full и empty. Допустим теперь, что потребитель, войдя в свой критический участок (mutex сброшен), обнару-живает, что буфер пуст. Он блокируется и начинает ждать появления сообщений. Но производитель не


Основы операционных систем 60

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

 

В сложных программах произвести анализ правильности использования семафоров с карандашом в руках становится очень непросто. В то же время обычные способы отладки программ зачастую не дают резуль-тата, поскольку возникновение ошибок зависит от interleaving атомарных операций, и ошибки могут быть трудновоспроизводимы. Для того чтобы облегчить работу программистов, в 1974 году Хором (Hoare) был предложен механизм еще более высокого уровня, чем семафоры , получивший название мо-ниторов. Мы с вами рассмотрим конструкцию, несколько отличающуюся от оригинальной.

 

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

 

monitor monitor_name {

 

описание внутренних переменных ;

 

void m1(...){...

 

}

void m2(...){...

}

...

void mn(...){...

}

 

{

 

блок инициализации внутренних переменных;

 

}

}

 

Здесь функции m1,..., mn представляют собой функции-методы монитора, а блок инициализации внутрен-них переменных содержит операции, которые выполняются один и только один раз: при создании мони-тора или при самом первом вызове какой-либо функции-метода до ее исполнения.

 

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

 

Однако одних только взаимоисключений недостаточно для того, чтобы в полном объеме реализовать ре-шение задач, возникающих при взаимодействии процессов. Нам нужны еще и средства организации оче-редности процессов , подобно семафорам full и empty в предыдущем примере. Для этого в мониторах бы-ло введено понятие условных переменных (condition variables)1), над которыми можно совершать две операции wait и signal, отчасти похожие на операции P и V над семафорами.


Дата добавления: 2021-01-21; просмотров: 95; Мы поможем в написании вашей работы!

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






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