Листинг 7.9. Реализация операций Р и V для однопроцессорной системы
type Semaphore = record
счетчик :integer:
указатель :pointer; продолжение
228________ Глава 7. Организация параллельных взаимодействующих вычислений
Листинг 7.9(продолжение)
end; var S :Semaphore;
procedure P ( var S : Semaphore); begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; Б.счетчик:= Б.счетчик-].: if S.счетчик < 0 then
WAIT(S); { вставить обратившийся процесс в список по S.указатель и передать
на процессор готовый к выполнению процесс } РАЗРЕШИТЬ_ПРЕРЫВАНИЯ end;
procedure V ( var S : Semaphore): begin ЗАПРЕТИТЬ ПРЕРЫВАНИЯ;
З.счетчик::= S.счетчик+1;
if S.счетчик <= 0 then RELEASE (S); { деблокировать первый процесс из списка по S.указатель }
РАЗРЕШИТЬ_ПРЕРЫВАНИЯ end:
procedure InitSem (var S ; Semaphore): begin
5.счетчик:=1;
5.указатель:=nil: end;
Реализация семафоров в мультипроцессорных системах сложнее, чем в однопроцессорных. Одновременный доступ к семафору S двух процессов, выполняющихся на однопроцессорной вычислительной системе, предотвращается запретом прерываний. Однако этот механизм не подходит для мультипроцессорных систем, так как он не препятствует двум или более процессам одновременно обращаться к одному семафору. В силу того что такой доступ должен реализовываться через критическую секцию, необходимо дополнительное аппаратное взаимное исключение доступа для различных процессоров. Одним из решений является использование уже знакомых нам неделимых команд проверки и установки (TS). Двухкомпонент-ный семафор в этом случае расширяется включением третьего компонента — логического признака взаимоискл (листинг 7.10).
Листинг 7.10.Реализация операций Р и V для мультипроцессорной системы
type Semaphore = record
счетчик : integer;
указатель : pointer;
взаимоискл : boolean: end; var S : Semaphore;
procedure InitSem (var S : Semaphore): begin With S do begin
счетчик:=1; указатель:=nil; взаимоискл:=true: end; end:
Средства синхронизации и связи взаимодействующих процессов_______________ 229
procedure Р ( var S : Semaphore): var разрешено : boolean: begin
ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ;
repeat ТS(разрешено, S.взаимоискл) until разрешено:
S.счетчик:=S.счетчик-1:
if S.счетчик < 0 then WAIT(S): { вставить обратившийся процесс в список по S.указатель
и передать на процессор готовый к выполнению процесс }
S.взаимоискл:=true;
РАЗРЕШИТЬ_ПРЕРЫВАНИЯ end:
procedure V ( var S : Semaphore ):
var разрешено : boolean:
begin
ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ;
repeat ТS(разрешено.S.взаимоискл) until разрешено:
5.Счетчик:=5.Счетчик+1;
if S.счетчик <= 0 then RELEASE(S): { деблокировать первый процесс из списка
по S.указатель }
S. взаимоискл:=true:
РАЗРЕШИТЬ__ПРЕРЫВАНИЯ: end:
Обратите внимание, что в данном тексте команда проверки и установки — TS(pa3-решено,S.взаимоискл) — работает не с целочисленными, а с булевыми значениями. Практически это ничего не меняет, ибо текст программы и ее машинная (двоичная) реализация — это разные вещи.
Мьютексы
Одним из вариантов реализации семафорных механизмов для организации взаимного исключения является так называемый мьютекс (mutex). Термин «mutex» произошел от словосочетания «mutual exclusion semaphore», что дословно переводится с английского как «семафор взаимного исключения». Мьютексы реализованы во многих операционных системах, их основное назначение — организация взаимного исключения для задач (потоков выполнения) одного или нескольких процессов. Мьютексы — это простейшие двоичные семафоры, которые могут находиться в одном из двух состояний — отмеченном и неотмеченном (открыт и закрыт соответственно). Когда какая-либо задача, принадлежащая любому процессу, становится владельцем объекта мьютекс, последний переводится в неотмеченное состояние. Если задача освобождает мьютекс, его состояние становится отмеченным.
Организация последовательного (а не параллельного) доступа к ресурсам с использованием мьютексов становится несложной, поскольку в каждый конкретный момент только одна задача может владеть этим объектом. Для того чтобы мьютекс стал доступен задачам (потокам выполнения), принадлежащим разным процессам, при создании ему необходимо присвоить имя, впоследствии передаваемое «по наследству» задачам, которые должны его использовать для взаимодействия. Для этого вводятся специальные системные вызовы (CreateMutex), в которых указываются начальное значение мьютекса, его имя и, возможно, атри-
230________ Глава 7. Организация параллельных взаимодействующих вычислений
буты защиты. Если начальное значение мьютекса равно true, считается, что задача, создающая этот объект, сразу будет им владеть. Можно указать в качестве начального значение false — в этом случае мьютекс не будет принадлежать ни одной из задач, и только специальным обращением к нему удастся изменить его состояние.
Для работы с мьютексом имеется несколько функций. Помимо уже упомянутой функции создания такого объекта (CreateMutex), есть функции открытия (OpenMu-tex), ожидания событий (WaitForSingleObject и WaitForMultipleObjects) и, наконец, освобождения этого объекта (ReleaseMutex).
Конкретные обращения к этим функциям и перечни передаваемых и получаемых параметров имеются в документации на соответствующую операционную систему.
Дата добавления: 2016-09-20; просмотров: 476;