Вот что на самом деле происходит, когда вы запускаете команду оболочки yes | sleep 10
.
Сначала оболочка создает анонимный канал , используя системный вызов pipe
.Системный вызов pipe
открывает два файловых дескриптора, которые являются концом чтения и концом записи канала.Все, что записывается в конец записи, становится доступным для чтения из конца чтения.
После этого оболочка создает два дочерних процесса, используя системный вызов fork
.Два дочерних элемента работают параллельно.
- В одном дочернем объекте оболочка подключает конец записи канала к стандартному выводу и закрывает конец чтения.Затем оболочка вызывает системный вызов
execve
, чтобы заменить изображение кода в этом процессе на кодовое изображение yes
.
Программа yes
записывает в канал столько времени, сколько может,Если на конце чтения канала нет активного read
вызова, вызов write
просто блокируется.(На самом деле есть небольшой буфер, который write
будет заполняться перед блокировкой, но здесь это не имеет значения.) - В другом дочернем объекте оболочка соединяет конец чтения канала канала со стандартным вводом и закрываетконец записи.Затем оболочка вызывает системный вызов
execve
, чтобы заменить изображение кода в этом процессе на изображение кода sleep
.Программа sleep
ничего не делает в течение 10 секунд. - Исходный процесс оболочки закрывает оба конца канала и ожидает выхода обоих дочерних элементов (используя системный вызов
wait
).
По истечении 10 секунд процесс, запущенный sleep
, завершается.На этом этапе конец чтения канала больше не открыт ни в одном процессе.Когда процесс пытается выполнить запись в канал, у которого конец чтения не открыт ни в одном процессе, ядро отправляет в процесс записи сигнал SIGPIPE
.Таким образом, процесс, выполняющий yes
, прерывается сигналом SIGPIPE.
В этот момент оболочка обнаруживает, что ее дочерние процессы по обе стороны конвейера завершены.Команда конвейера возвращает состояние правой стороны, которое равно 0 (sleep
успешно завершается).
, поскольку sleep не читает из stdin, канал, соединяющий оба процесса, заполняется ивызвать yes, чтобы блокировать на неопределенный срок, когда он пытается выполнить запись в теперь заполненный каналвыполняется первым и записывает данные в канал до того, как процесс ожидания будет запущен, и, таким образом, ни один процесс не будет подключен к концу чтения канала
Это неверно в нескольких местах.yes
не использует неблокирующий ввод-вывод.Он выполняется параллельно с sleep
, а не первым.Никогда не наступает момент времени, когда ни один процесс не будет подключен к концу чтения канала, только до выхода sleep
.В зависимости от времени, возможно, что yes
начнет запись до того, как sleep
начнет выполняться, возможно, даже до того, как дочерний процесс для программы sleep
будет разветвлен, но конец чтения стал открытым, когда вернулся вызов pipe
,в то время как конец записи стал открытым.