Я изо всех сил пытался понять концепцию, включающую команды dup2()
, exec()
и каналы вместе.
То, чего я пытаюсь достичь:
По конвейеру вывод программы X поступает на вход программы Y.
Что-нибудь базовое, например who | sort
с родителем и 2 дочерними элементами, при этом дети несут ответственность за выполнение программ, а родитель передает программы дочерним элементам.
Вот чего я не понимаю в трубах:
P1) Каналы обрабатываются как файлы и должны быть однонаправленными, но что мешает мне использовать один канал для нескольких однонаправленных каналов связи? Итак, скажем, у меня есть pipe1
и три процесса (P
- родительский - C1
, C2
, дочерние), у которых канал открыт путем разветвления. Все эти процессы используют файловые дескрипторы. Допустим, мы все делаем правильно, закрываем неиспользуемые концы труб, P
теперь что-то пишет в C1
. В чем проблема с использованием канала для связи между C1
и C2
снова? Как раз во время написания этого вопроса меня осенила идея: есть ли проблема с тем, кто читает из него, в то время как многие процессы могут открывать его одновременно (два процесса блокируются для чтения), т.е. система не может точно сказать, кто хочет прочитать записанные в нее буферизованные данные? Если да, то как это реализовано в системе?
Я действительно пытаюсь понять эту концепцию, поэтому, пожалуйста, потерпите меня.
Чтобы применить этот вопрос к реальной жизни, вот какой-то псевдокод, с которым я имею дело:
P:
P
закрывает ненужный конец чтенияpipe1
P
отправляет программный аргумент ('who')C1
черезpipe1
P
закрывает конец записиP
ждет выхода детей
C1:
C1
читает аргумент с конца чтенияpipe1
C1
dup2()
расширяет стандарт до конца записиpipe1
C1
закрывает оба концаpipe1
(потому что мы его уже обманули)C1
execvp()
s программа ('кто')
C2:
C2
dup2()
s читает конецpipe1
наstdin
, чтобы получить ввод для программы, которая будет выполнятьсяC2
закрывает оба концаpipe1
C2
ожидает ввода наstdin
изC1
отdup
edpipe1
C2
execvp()
s программа ('sort') с этим входом
Теперь, если бы я сделал это, как описано выше, мне бы не повезло. Однако, если я представил другой канал
pipe2
, он будет выглядеть примерно так: P:
P
закрывает оба конца ненужной трубыpipe2
P
закрывает ненужный конец чтенияpipe1
P
отправляет программный аргумент ('who') вC1
черезpipe1
P
закрывает конец записиP
ждет выхода детей
C1:
C1
закрывает конец чтенияpipe2
C1
читает аргумент с конца чтенияpipe1
C1
dup2()
s стандарт до конца записиpipe2
C1
закрывает конец записиpipe2
C1
закрывает оба концаpipe1
- сpipe2
,pipe1
в этом дочернем элементеC1
execvp()
s программа ('кто')
C2:
C2
dup2()
s читать с концаpipe2
поstdin
C2
закрывает оба концаpipe1
C2
ожидает ввода наstdin
изC1
отdup
edpipe2
C2
выполняет программуsort
с этим входом
Верно ли предположение, что каналы не следует повторно использовать в нескольких процессах, потому что система может не знать, кого «обслуживать»? Или этому есть какая-то другая причина?
a | b
, затем создает C1 и C2, C1 выполняет a, C2 выполняет b. stdout a должен быть stdin b. Я прав? Это требование? Разве P не может форкнуть C1, а C1 может форкнуть C2? - person holgac   schedule 25.04.2015exec
не продолжается после указанной операции, поэтому C1 и C2 прекратят работу после выполнения команд. Это означает, что всякий раз, когда P получает новый ввод, напримерa | b
, ему придется снова выполнить форк. Поскольку это так, связь между P и C1 и P и C2 кажется здесь избыточной. - person holgac   schedule 25.04.2015exec()
заменяет текущий процесс. Родитель должен сообщить программы детям, это требование. - person the_critic   schedule 25.04.2015