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