Пример работы с семафорами
Теперь продолжим пример, который начали с процедуры initsem. Он содержит две процедуры р() и v(), реализующие традиционные операции над семафорами. Сначала рассмотрим р():
{$i pv.inc}
(* Процедура p.pas - операция p для семафора *)
function p (semid:longint):longint;
var
p_buf:tsembuf;
begin
p_buf.sem_num := 0;
p_buf.sem_op := -1;
p_buf.sem_flg := SEM_UNDO;
if not semop (semid, @p_buf, 1) then
begin
perror ('ошибка операции p(semid)');
halt (1);
end;
p:=0;
end;
Обратите внимание на то, что здесь использован флаг SEM_UNDO. Теперь рассмотрим текст процедуры v().
{$i pv.inc}
(* Процедура v.pas - операция v для семафора *)
function v (semid:longint):longint;
var
v_buf:tsembuf;
begin
v_buf.sem_num := 0;
v_buf.sem_op := 1;
v_buf.sem_flg := SEM_UNDO;
if not semop (semid, @v_buf, 1) then
begin
perror ('Ошибка операции v(semid)');
halt (1);
end;
v:=0;
end;
Можно продемонстрировать использование этих довольно простых процедур для реализации взаимного исключения. Рассмотрим следующую программу:
(* Программа testsem - проверка процедур работы с семафорами *)
uses ipc,stdio,linux;
{$i pv.inc}
procedure handlesem (skey:tkey);
var
semid, pid:longint;
begin
pid := getpid;
semid := initsem (skey);
if semid < 0 then
halt (1);
writeln (#$a'Процесс ',pid,' перед критическим участком');
p (semid);
writeln ('Процесс ',pid,' выполняет критический участок');
(* В реальной программе здесь выполняется нечто осмысленное *)
sleep (10);
writeln ('Процесс ',pid,' покинул критический участок');
v (semid);
writeln ('Процесс ',pid,' завершает работу');
halt (0);
end;
const
semkey:tkey = $200;
var
i:integer;
begin
for i := 1 to 3 do
if fork = 0 then
handlesem (semkey);
end.
Программа testsem порождает три дочерних процесса, которые используют вызовы р() и v() для того, чтобы в каждый момент времени только один из них выполнял критический участок. Запуск программы testsem может дать следующий результат:
Процесс 799 перед критическим участком
Процесс 799 выполняет критический участок
Процесс 800 перед критическим участком
Процесс 801 перед критическим участком
Процесс 799 покинул критический участок
Процесс 801 выполняет критический участок
Процесс 799 завершает работу
Процесс 801 покинул критический участок
Процесс 801 завершает работу
Процесс 800 выполняет критический участок
Процесс 800 покинул критический участок
Процесс 800 завершает работу