Давайте вернемся назад к примеру с
каналами, поскольку он весьма интересен, а
также является хорошей иллюстрацией для
понимания ссылок. Когда вы в командной
строке используете канал, 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'а - нет)[5]. Команда для создания именованного
канала - 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 выполнилась позже, и вы увидели ее вывод только после возвращения.
[5] Существуют и другие различия между этими двумя типами каналов, но это выходит за рамки данной книги.