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

Размер канала


Пока в примерах передавались только небольшие объемы данных. Важно заметить, что на практике размер буфера канала конечен. Другими словами, только определенное число байтов может находиться в канале, прежде чем следующий вызов fdwrite будет заблокирован. Минимальный размер, определенный стандартом POSIX, равен 512 байтам. В большинстве существующих систем это значение намного больше. При программировании важно знать максимальный размер канала для системы, так как он влияет на оба вызова fdwrite и fdread. Если вызов fdwrite выполняется для канала, в котором есть свободное место, то данные посылаются в канал, и немедленно происходит возврат из вызова. Если же в момент вызова fdwrite происходит переполнение канала, то выполнение процесса обычно приостанавливается до тех пор, пока место не освободится в результате выполнения другим процессом чтения из канала.

Приведенная в качестве примера следующая программа записывает в канал символ за символом до тех пор, пока не произойдет блокировка вызова fdwrite. Программа использует вызов alarm для предотвращения слишком долгого ожидания в случае, если вызов fdread никогда не произойдет. Необходимо обратить внимание на использование процедуры fpathconf, служащей для определения максимального числа байтов, которые могут быть записаны в канал за один прием.

(* Запись в канал до возникновения блокировки записи *)

uses linux,stdio;

var

  count:integer;

(* Вызывается при получении сигнала SIGALRM *)

procedure alrm_action(signo:integer);cdecl;

begin

  writeln ('Запись блокируется после вывода ',count,' символов');

  halt (0);

end;

const



  c:char='x';

var

  fdin,fdout,pipe_size:longint;

  act:sigactionrec;

  temp:sigset_t;

begin

  (* Задать обработчик сигнала *)

  act.handler.sh := @alrm_action;

  sigfillset (@temp);

  act.sa_mask:=temp.__val[0];

  (* Создать канал *)

  if not assignpipe (fdin,fdout) then

  begin

    perror ('Ошибка вызова pipe ');

    halt (1);

  end;

  (* Определить размер канала *)




  pipe_size := fpathconf (fdin, _PC_PIPE_BUF);

  writeln('Максимальный размер канала: ',pipe_size,' байт');

  (* Задать обработчик сигнала *)

  sigaction (SIGALRM, @act, nil);

  while true do

  begin

    (* Установить таймер *)

    alarm (20);

    (* Запись в канал *)

    fdwrite (fdout, c, 1);

    (* Сбросить таймер *)

    alarm (0);

    inc(count);

    if count mod 1024 = 0 then

      writeln (count, ' символов в канале');

  end;

end.

Вот результат работы программы на некоторой системе:

Максимальный размер канала: 32768 байт

1024 символов в канале

2048 символов в канале

3072 символов в канале

4096 символов в канале

5120 символов в канале

.

.

.

31744 символов в канале

32768 символов в канале

Запись блокируется после вывода 32768 символов

Обратите внимание, насколько реальный предел больше, чем заданный стандартом POSIX минимальный размер канала.

Ситуация становится более сложной, если процесс пытается записать за один вызов fdwrite больше данных, чем может вместить даже полностью пустой канал. В этом случае ядро вначале попытается записать в канал максимально возможный объем данных, а затем приостанавливает выполнение процесса до тех пор, пока не освободится место под оставшиеся данные. Это важный момент: обычно вызов fdwrite для канала выполняется неделимыми порциями (atomically), и данные передаются ядром за одну непрерываемую операцию. Если делается попытка записать в канал больше данных, чем он может вместить, то вызов fdwrite выполняется поэтапно. Если при этом несколько процессов выполняют запись в канал, то данные могут оказаться беспорядочно перепутанными.

Взаимодействие вызова fdread с каналами является более простым. При выполнении вызова fdread система проверяет, является ли канал пустым. Если он пуст, то вызов fdread будет заблокирован до тех пор, пока другой процесс не запишет в канал какие-либо данные. При наличии в канале данных произойдет возврат из вызова fdread, даже если запрашивается больший объем данных, чем находится в канале.


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