Как я могу объединить два отсортированных именованные каналы с неравными размерами?

Если echoing или yesing ввода в интерактивную программу не достаточно, чтобы обмануть ее, это обычно потому, что она пытается быть умной и проверяет, является ли ее ввод действительно терминалом или трубой. Для этого нужен молоток побольше; тот, которым обычно орудуют люди, это expect, который был написан для обхода этой проблемы.

1
06.06.2019, 18:16
1 ответ

Очевидно, что ваша программа создает взаимоблокировку, когда вы записываете разные объемы данных в два именованных канала. Ваша программа блокируется на 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.

2
27.01.2020, 23:30

Теги

Похожие вопросы