Неименованные каналы

Неименованные каналы используются для обмена информацией между родственными процессами (родитель и любые его потомки). С одного конца в канал можно только записывать информацию, а с другого конца - только читать.
Между "обычными" файлами и неименованными каналами существует ряд различий:

  • Прочитанная информация немедленно удаляется из канала и становится недоступна для повторного чтения
  • При создании файла - создается один файловый дескриптор, при создании канала создаются два дескриптора - для передачи (записи) в канал и для приема (чтения) из канала.

При порождении дочерних процессов файловые дескрипторы наследуются - это позволяет дочерним процессам взаимодействовать как с родительским процессом, так и между собой.
Данные в канале организованы по принципу FIFO - информация, которая первой записана в канал, будет первой прочитана из канала.

Неименованные каналы широко используются в операционной системe. Например, командный интерпретатор использует их для организации конвейерной обработки.

$ cat /var/log/apt/term.log | wc
     32     243    2354

Утилита cat читает текстовый файл term.log и передает последовательный поток символов программе wc, которая подсчитывает число строк, слов и символов в файле.

Утилита архивирования tar использует неименованные каналы для упаковки архивов "на лету" при помощи "внешних" упаковщиков.

$ strace -fe pipe,execve tar cJf ./50GB.zip .
execve("/bin/tar", ["tar", "cJf", "./50GB.zip", "."], 0x7fffd3f85858 /* 70 vars */) = 0
pipe([3, 4])                            = 0
strace: Process 15323 attached
[pid 15323] execve("/bin/sh", ["/bin/sh", "-c", "xz"], 0x7ffcf642f850 /* 70 vars */) = 0
strace: Process 15324 attached
[pid 15324] execve("/usr/bin/xz", ["xz"], 0x56374b062148 /* 70 vars */) = 0
[pid 15324] pipe([3, 4])                = 0
^Z
[1]+  Stopped                 strace -fe pipe,execve tar cJf ./50GB.zip .

В показанном выше примере с помощью strace отслеживается системный вызов pipe, при помощи которого tar создает неименованный канал для связи с упаковщиком xz в дочернем процессе. Затем группа процессов архиватора приостанавливается с помощью SIGTSTP (^Z).

29031 pts/4    Ss 0:00  |   |   \_ /bin/bash
15320 pts/4    T  0:00  |   |   |   \_ strace -fe pipe,execve tar cJf ./50GB.zip .
15322 pts/4    t  0:00  |   |   |   |   \_ tar cJf ./50GB.zip .
15323 pts/4    t  0:00  |   |   |   |       \_ /bin/sh -c xz
15324 pts/4    t  0:02  |   |   |   |           \_ xz
15349 pts/4    R+ 0:00  |   |   |   \_ ps f

С помощью команды lsof показаны файловые дескрипторы открытых файлов обоих процессов.

$ lsof -p 15322
COMMAND   PID   USER  FD  TYPE  DEVICE  SIZE/OFF  NODE    NAME
...
tar       15322 agr   4w  FIFO  0,12    0t0       2518136 pipe

$ lsof -p 15324
COMMAND   PID   USER  FD  TYPE  DEVICE  SIZE/OFF  NODE    NAME
...
xz        15324 agr   0r  FIFO  0,12    0t0       2518136 pipe

Важно отметить, что в процессе архиватора PID=15322 файловый дескриптор передающей части канала сохранил свой номер, а в дочернем процессе упаковщика PID = 15324 файловый дескриптор принимающей части канала был перенаплавлен в STDIN, как того и ожидает упаковщик xz.

Комментарии