Монитор, реализующий двоичный семафор.
Рассмотрим монитор, с помощью которого реализуется алгоритм выполнения операций Р и V над семафором S. Этот алгоритм известен, как алгоритм Хоара.
В мониторе содержится одна или несколько допускающих параллельное использование процедур со статическими глобальными информационными структурами. При первом обращении монитор присваивает своим переменным из этих структур начальные значения. При каждом последующем обращении, используются те значения переменных, которые остались от предыдущего обращения. Следует подчеркнуть, что монитор - это пассивный объект, а не процесс, монитор оживает только тогда, когда какой-либо процесс допускается воспользоваться его услугами.
Monitor Семафор;
S : integer;
S_positive: condition; {переменная-условие, которая указывает, когда
заблокированный процесс может продолжать работу}
procedure P;
begin
if S<1 then Wait(S_ positive);{ожидание выполнения
условия}
S:=S-1
end;
procedure V;
begin
S:=S+1;
if S=1 then Signal(S_POSITIVE);{сигнал о выполнении
условия}
end;
begin
S:=1
end;
Рассмотрим, каким образом, при помощи приведенного монитора Хоара можно организовать взаимоисключение двух процессов. Здесь вызовы процедур P или V монитора будем указывать как Семафор.Р или Семафор.V.
begin
Parbegin
процесс_Х:
begin
While (true) do
begin
Call (семафор.Р);
{Критический участок процесса_Х};
Call(семафор.V);
{Оставшиеся операторы процесса_Х}
end
end;
процесс_Y;
begin
While (true) do
begin
Call (семафор.Р);
{Критический участок процесс_Y};
Call(семафор.V);
{Оставшиеся операторы процесса_Y}
end
end
Parend
end.
Семантика монитора гарантирует, что если хотя бы один процесс ожидает выполнения условия, то никакой другой обратившийся процесс не может вмешаться между сигналом о выполнении этого условия и продолжением ровно одного из ожидающих процессов. Хотя по сравнению с семафорами, мониторы не представляют собой более мощного инструмента синхронизации, у них есть некоторые преимущества. Во-первых, доступ к разделяемым переменным всегда ограничен телом монитора, что автоматически исключает критические участки.
Решение задачи передачи данных одного процесса другому при помощи монитора (случай кольцевого буфера)
Рассмотрим в этом разделе так называемый кольцевой буфер (ring buffer) и покажем, каким образом он может использоваться в случаях, когда процесс-производитель должен передавать данные процессу-потребителю.
В качестве кольцевого буфера, куда процесс-производитель помещает данные, используем массив buffer заданного размера N.
Поскольку размер буфера ограничен, процесс-производитель в какой-то момент может столкнуться с тем, что все элементы массива окажутся занятыми - в этом случае ему необходимо подождать, пока процесс-потребитель не прочитает и тем самым не освободит хотя бы один элемент массива.
Аналогично может возникнуть ситуация, когда процесс-потребитель хотел бы прочитать данные, а массив оказывается пустым - в этом случае процесс-потребитель должен ждать, пока процесс-производитель не поместит данные в массив.
monitor Кольцевой_буфер;
var buffer : array [0..N-1] of Тип_данных;
Tpos : 0..N; {текущая позиция в буфере}
Zpos, Opos : 0..N-1; {соответственно, очередная
заполняемая и очередная освобождаемая позиции
в буфере}
bufnp, bufnz : condition; { переменные-условия,
bufnz- буфер незаполнен, является признаком,
которого ждет производитель, если обнаружит,
что буфер целиком заполнен, он
устанавливается по сигналу потребителя о том,
что тот только что освободил позицию;
bufnp- буфер непуст, является признаком,
которого ждет потребитель, если обнаружит,
что буфер пуст, этот признак устанавливается
по сигналу производителя о том, что он только
что поместил данные в некоторую позицию
буфера }
Procedure Заполнить_позицию (Данные:Тип данных) ;
begin
if Tpos = N then Wait(bufnz){ожидание сигнала- буфер
незаполнен};
buffer[Zpos] := Данные;
Tpos:=Tpos+1;
Zpos:=(Zpos +1) mod N;
Signal(bufnp){сигнал, оповещающий, о том, что буфер непуст}
end
Procedure Ocвободить_позицию ( var Данные: Тип данных) ;
begin
if Tpos=0 then Wait(bufnp);{ожидание сигнала- буфер непуст}
Данные := buffer[Opos];
Tpos:=Tpos-1;
Opos:= (Opos+1) mod N;
Signal(bufnz){сигнал, оповещающий о том, что буфер
незаполнен}
end;
begin
Tpos:=0;
Opos:=0;
Zpos:=0
end;
Механизам кольцевого буфера весьма удобен для реализации управления спулингом (вводом-выводом с буферизацией) в ОС.
Решение задачи передачи данных одного процесса другому при помощи монитора (случай информационной базы)
В вычислительных системах обычно имеются “процессы-читатели” и “процессы-писатели”(readers and writers) , если первые читают данные из информационной базы, то вторые, записывают данные в информационные базы. Заметим, что процессы-читатели не изменяют содержимого базы и могут обращаться к ней одновременно. А процесс-писатель может изменять данные, поэтому он должен иметь монопольный, исключительный доступ к базе данных.
monitor Читатели_Писатели;
var
Readers : integer;{переменная указывает количество активных читателей, когда Readers= 0, ожидающий процесс-писатель получает возможность начать работу}
SmbWrite : boolean;{somebody write - когда кто-то пишет
эта
переменная имеет истинное значение}
PermRead,
PermWrite : condition; {permission read/write - пока не появится истинное значение условия читать разрешается,PermRead - процесс-читатель не может продолжить свое выполнение; пока не появится истинное значение условия писать разрешается, PermWrite - процесс-писатель не может продолжить свое выполнение}
Procedure Начало_Чтения;
begin
if (SmbWrite) or (Очередь(PermWrite))
then Wait(PermRead);{ожидание сигнала - читать разрешается}
Readers:=Readers+1;
Signal(PermRead);{сигнал, оповещающий о возможности чтения}
end;
Procedure Конец_Чтения;
begin
Readers:=Readers-1;
If Readers=0 then Signal(PermWrite);{сигнал, оповещающий о
возможности записи}
end;
Procedure Начало_Записи;
begin
if (Readers>0) or (SmbWrite)
then Wait(PermWrite);{ожидание сигнала - писать разрешается}
SmbWrite:=true
end;
Procedure Конец_Записи;
begin
SmbWrite:=false;
if Очередь(PermRead)
then Signal(PermRead) {сигнал, оповещающий о возможности
чтения}
else Signal(PermWrite);{сигнал, оповещающий и возможности
записи}
end;
begin
Readers:=0;
SmbWrite:=false
end;
Когда процессу-читателю нужно произвести чтение, он вызывает процедуру монитора под названием Начало_Чтения, а после завершения чтения - процедуру Конец_Чтения. После входа в процедуру Начало_Чтения новый процесс-читатель сможет продолжить свою работу, если нет процесса-писателя, производящего в данный момент запись или ожидающего очереди на запись. Второе из этих условий необходимо для того, чтобы предотвратить возможность бесконечного откладывания ожидающих процессов-писателей. Отметим, что процедура Начало_Чтения завершается выдачей сигнала разрешающего чтение, PermRead, чтобы следующий, ожидающий в очереди читатель мог начать чтение. Причем во время выполнения такой цепочки действий все вновь приходящие процессы включаются в очередь ожидания.
Когда процесс завершает операцию чтения, он вызывает процедуру Конец_Чтения, которая уменьшает число читателей на 1 и, в конце концов количество процессов-читателей становится равным 0; в этот момент вырабатывается сигнал разрешающий запись, PermWrite, и следующий процесс-писатель получает возможность продолжать работу.
Когда процессу-писателю нужно произвести запись, он вызывает процедуру Начало_Записи. Поскольку процесс-писатель должен иметь монопольный доступ к информации, то если в настоящий момент есть уже работающие процессы-читатели или какой-либо активизированный процесс-писатель, данному процессу-писателю придется ждать выдачи сигнала PermWrite. Когда же писатель получает возможность продолжить работу, переменная SmbWrite:=true.
Когда процесс-писатель заканчивает свою работу, он устанавливает SmbWrite:=false, тем самым, открывая вход в монитор для других процессов.
Писатель, завершивший работу, проверяет, в первую очередь, нет ли ожидающего читателя - если есть, он выдает сигнал PermRead, так что ожидающий читатель получает возможность продолжить работу. Если читателей нет, то выдается сигнал PermWrite и получает возможность продолжить работу ожидающий процесс-писатель.
Дата добавления: 2017-01-29; просмотров: 663;