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



 

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

 

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


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

ременной, то активным становится только один из них. Что можно предпринять для того, чтобы у нас не оказалось двух процессов, разбудившего и пробужденного, одновременно активных внутри монитора ? Хор предложил , чтобы пробужденный процесс подавлял исполнение разбудившего процесса, пока он сам не покинет монитор. Несколько позже Хансен (Hansen) предложил другой механизм: разбудивший процесс покидает монитор немедленно после исполнения операции signal. Мы будем придерживаться подхода Хансена.

 

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

 

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

 

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 и т. д. Эмуляция мониторов с помощью системных вызовов для обычных широко используемых языков про-граммирования не так проста, как эмуляция семафоров. Поэтому можно пользоваться еще одним меха-низмом со скрытыми взаимоисключениями, механизмом, о котором мы уже упоминали, – передачей со-общений.

 

Сообщения

 

Для прямой и непрямой адресации достаточно двух примитивов, чтобы описать передачу сообщений по линии связи – send и receive. В случае прямой адресации мы будем обозначать их так:

 

send(P, message) – послать сообщение message процессу P; receive(Q, message) – получить сообщение message от процесса Q.


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

В случае непрямой адресации мы будем обозначать их так:

 

send(A, message) – послать сообщение message в почтовый ящик A; receive(A, message) – получить сообщение message из почтового ящика A.

 

Примитивы send и receive уже имеют скрытый от наших глаз механизм взаимоисключения. Более того, в большинстве систем они уже имеют и скрытый механизм блокировки при чтении из пустого буфера и при записи в полностью заполненный буфер. Реализация решения задачи producer-consumer для таких примитивов становится неприлично тривиальной. Надо отметить, что, несмотря на простоту использова-ния, передача сообщений в пределах одного компьютера происходит существенно медленнее, чем работа с семафорами и мониторами.

 

Эквивалентность семафоров, мониторов и сообщений


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

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






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