Если echo
ing или yes
ing ввода в интерактивную программу не достаточно, чтобы обмануть ее, это обычно потому, что она пытается быть умной и проверяет, является ли ее ввод действительно терминалом или трубой. Для этого нужен молоток побольше; тот, которым обычно орудуют люди, это expect, который был написан для обхода этой проблемы.
Очевидно, что ваша программа создает взаимоблокировку, когда вы записываете разные объемы данных в два именованных канала. Ваша программа блокируется на write
для одного fifo2 (с полным буфером ), а процесс sort
блокируется на read
для fifo1 (с пустым буфером ).
Вы не знаете, как реализован sort
. Вероятно, он хочет читать файлы большими блоками, а затем обрабатывать данные в памяти для повышения эффективности. Буферизация может даже происходить автоматически, если sort
использует функции из stdio.h
для чтения данных.
Именованные (и неименованные )каналы используют буфер для данных.
Если буфер заполнен, процесс записи будет заблокирован до тех пор, пока процесс чтения не прочитает некоторые данные или не закроет его конец.
Если буфер пуст, процесс чтения будет заблокирован до тех пор, пока процесс записи не запишет некоторые данные или не закроет его конец.
Если вы записываете одну строку в fifo1 и две строки в fifo2 в каждом цикле, вы заполните буфер fifo2, в то время как буфер fifo1 заполнен только наполовину -.
В зависимости от того, сколько данных ваша программа записывает в fifos и сколько sort
хочет прочитать, это, очевидно, приводит к ситуации, когда sort
хочет прочитать что-то из fifo1, который просто имеет пустой буфер, в то время как ваша программа хочет писать в fifo2 с полным буфером.
Результат является детерминированным, поскольку буфер конвейера имеет фиксированный размер и, возможно, ваша программа и sort
используют фиксированные размеры буфера для чтения или записи данных.
Вы можете посмотреть исходный код GNU sort
по адресу
https://github.com/wertarbyte/coreutils/blob/master/src/sort.c
Вначале он пытается заполнить входные буферы для всех входных файлов в цикле по всем файлам, используя функцию fillbuf
.
Позже, при некоторых условиях, он снова вызывает fillbuf
для входного файла.
В функции fillbuf
есть комментарий
/* Read as many bytes as possible, but do not read so many
bytes that there might not be enough room for the
corresponding line array. The worst case is when the
rest of the input file consists entirely of newlines,
except that the last byte is not a newline. */
Судя по всему, sort
выбирает один из входных файлов и хочет получить определенный объем данных. Он не переключает входные файлы при чтении блоков.
Реализация хорошо работает для обычных файлов, потому что операция read
либо возвращает некоторые данные, либо EOF через некоторое время, поэтому она не будет заблокирована навсегда.
Всегда трудно избежать взаимоблокировок, если у вас есть более одной вещи, которая может блокироваться между двумя процессами/потоками. В вашем случае вы должны использовать только одну трубу. Использование неблокирующих операций -может помочь, если у вас всегда есть данные для записи в fifo1, если fifo2 блокируется, или наоборот.
Использование двух каналов может работать, если вы будете использовать два отдельных потока/процесса для записи в каналы, но только если потоки/процессы работают независимо друг от друга. Не помогло бы, если бы поток A, который должен писать в pipe1, каким-то образом ждал бы потока B, который просто блокируется при записи в pipe2.