Мониторы

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

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

monitor monitor_name

{

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

void m1(...) {..}

void m2(...) {...}

...

void mn(...) {...}

{

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

}

}

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

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

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

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

Когда ожидаемое событие происходит, другой процесс внутри функции-метода совершает операцию signal над той же самой условной переменной. Это приводит к пробуждению ранее заблокированного процесса, и он становится активным. Если несколько процессов дожидались операции signal для этой переменной, то активным становится только один из них. Чтобы не оказалось двух процессов, разбудившего и пробужденного, одновременно активных внутри монитора, Хоар предложил, чтобы пробужденный процесс подавлял исполнение разбудившего процесса, пока он сам не покинет монитор. Несколько позже Хансен предложил другой механизм: разбудивший процесс покидает монитор немедленно после исполнения операции signal. Остановимся на подходе Хансена.

Применим концепцию мониторов к решению задачи производитель-потребитель.

monitor ProducerConsumer

{

condition full, empty;

int count;

void put()

{

if(count == N) full.wait;

put_item;

count += 1;

if(count == 1) empty.signal;

}

void get()

{

if (count == 0) empty.wait;

get_item();

count -= 1;

if(count == N-1) full.signal;

}

{

count = 0;

}

}

Producer:

while(1)

{

produce_item;

ProducerConsumer.put();

}

Consumer:

while(1)

{

ProducerConsumer.get();

consume_item;

}

Приведенный пример решает поставленную задачу.

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: