Системное программирование в UNIX средствами Free Pascal

       

Пример работы с семафорами


Теперь продолжим пример, который начали с процедуры 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 завершает работу



Содержание раздела