4. «Анонимные» каналы и именованные каналы

Давайте вернемся назад к примеру с каналами, поскольку он весьма интересен, а также является хорошей иллюстрацией для понимания ссылок. Когда вы в командной строке используете канал, shell создает для вас канал и работает так, что команда перед каналом выполняет в него запись, а команда после канала выполняет из него чтение. Все каналы, будь они анонимными (как те, что используются в shell'ах) или именованными (смотрите ниже), работают согласно принципу простой очереди FIFO (First In, First Out, «первым пришел - первым обслужен»). Мы уже видели примеры использования каналов в shell'е, но давайте взглянем еще на один пример для демонстрации этого принципа:

$ ls -d /proc/[0-9] | head -5
/proc/1/
/proc/2/
/proc/3/
/proc/4/
/proc/5/

Одно обстоятельство, которое вы не заметите в этом примере (потому что это происходит слишком быстро), состоит в блокировке записей в каналы. Это означает, что когда команда ls выполняет запись в канал, он блокируется до тех пор, пока процесс выполняет чтение на другом конце. Чтобы увидеть этот эффект, вы можете создать именованные каналы, которые, в отличие от каналов, используемых shell'ами, имеют имена (т.е. они являются связанными, в то время как каналы shell'а - нет)[56]. Команда для создания именованного канала - mkfifo:

$ mkfifo a_pipe
$ ls -il
total 0
169 prw-rw-r--  1 queen queen 0 Aug  6 19:37 a_pipe|
  #
  # Вы можете видеть, что счётчик ссылок равен 1,
  # а файл является каналом ('p').
  #
  # Вы также можете использовать здесь ln:
  #
  # You can also use ln here:
  #
$ ln a_pipe the_same_pipe
$ ls -il
total 0
169 prw-rw-r--  2 queen queen 0 Aug  6 19:37 a_pipe|
169 prw-rw-r--  2 queen queen 0 Aug  6 19:37 the_same_pipe|
$ ls -d /proc/[0-9] >a_pipe
  #
  # Процесс заблокирован, т.к. на другом конце нет считывающей программы.
  # Нажмите Control Z, чтобы приостановить процесс...
  #
[1]+  Stopped                 ls -F --show-control-chars --color=auto -d /proc/[0-9] >a_pipe
  #
  # ...Затем отправьте его в фоновый режим:
  #
$ bg
[1]+ ls -F --show-control-chars --color=auto -d /proc/[0-9] >a_pipe &
  #
  # теперь выполняем чтение из канала...
  #
$ head -5 <the_same_pipe
  #
  # ...процесс записи завершается
  #
/proc/1/
/proc/2/
/proc/3/
/proc/4/
/proc/5/
[1]+  Done                    ls -F --show-control-chars --color=auto -d /proc/[0-9] >a_pipe
$

Аналогичным образом чтение тоже блокируется. Если мы выполним приведенные выше команды в обратном порядке, мы увидим что команда head блокируется, ожидая, чтобы какой-либо процесс дал ей что-нибудь прочитать:

$ head -5 <a_pipe 
# 
# Программа заблокировалась, приостановите её: C-z 
# 
[1]+  Stopped                 head -5 <a_pipe 
# 
# Отправляем её в фоновый режим... 
# 
$ bg 
[1]+ head -5 <a_pipe &
# 
# ...И скармливаем ей что-нибудь :) 
# 
$ ls -d /proc/[0-9] >the_same_pipe 
/proc/1/ 
/proc/2/ 
/proc/3/ 
/proc/4/ 
/proc/5/ 
[1]+  Done                    head -5 <a_pipe
$

Вы также можете увидеть нежелательный эффект в предыдущем примере: команда ls завершилась до того, как вступила в действие команда head. В результате вы немедленно возвратились в приглашение консоли, а head выполнилась позже, и вы увидели ее вывод только после возвращения.



[56] Существуют и другие различия между этими двумя типами каналов, но это выходит за рамки данной книги.