Давайте вернемся назад к примеру с каналами, поскольку он весьма интересен, а
также является хорошей иллюстрацией для понимания ссылок. Когда вы в
командной строке используете канал, 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
'а - нет)[26]. Команда для создания именованного канала -
mkfifo:
$ mkfifo a_pipe $ ls -il total 0 169 prw-rw-r-- 1 queen queen 0 Dec 10 14:12 a_pipe| # # Вы можете видеть, что счетчик ссылок равен 1, # а файл является каналом ('p'). # # Вы также можете использовать здесь ln: # $ ln a_pipe the_same_pipe $ ls -il total 0 169 prw-rw-r-- 2 queen queen 0 Dec 10 15:37 a_pipe| 169 prw-rw-r-- 2 queen queen 0 Dec 10 15:37 the_same_pipe| $ ls -d /proc/[0-9] >a_pipe # # Процесс заблокирован, т.к. на другом конце нет считывающей программы. # Нажмите Control Z, чтобы приостановить процесс... # [1]+ Stopped ls -d /proc/[0-9] >a_pipe # # ...Затем отправьте его в фоновый режим: # $ bg [1]+ ls -d /proc/[0-9] >a_pipe & # # теперь выполняем чтение из канала... # $ head -5 <the_same_pipe # # ...процесс записи завершается.... # /proc/1/ /proc/2/ /proc/3/ /proc/4/ /proc/5/ [1]+ Done ls -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/ $
Вы также можете увидеть нежелательный эффект в предыдущем примере: команда ls завершилась до того, как вступила в действие команда head. В результате вы немедленно возвратились в приглашение консоли, а head выполнилась позже, и вы увидели ее вывод только после возвращения.
[26] Существуют и другие различия между этими двумя типами каналов, но это выходит за рамки данной книги.