Ответ вслух Senior Потоки и пайпы обновлено

Как устроен пайп

Вопрос

Что происходит, когда shell выполняет a | b? Расскажи про процессы, буфер и сигналы.

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Shell вызывает pipe() и получает два дескриптора: на запись и на чтение. Потом делает fork для каждой команды, в первом процессе подменяет stdout на конец записи, во втором stdin на конец чтения, и оба выполняют exec.

Что должно прозвучать в ответе

  • Shell создаёт пайп (`pipe()`), делает fork для каждой команды и подключает stdout `a` и stdin `b` к концам пайпа

  • Команды работают одновременно, данные идут через буфер ядра (по умолчанию 64 КиБ в Linux)

  • Полный буфер блокирует писателя, пустой блокирует читателя: естественный backpressure

  • Если читатель закрылся, писатель получает SIGPIPE/EPIPE

  • Код конвейера по умолчанию от последней команды, `pipefail` и `PIPESTATUS` дают остальные

  • Буферизация stdio меняется: в пайп пишут блоками, отсюда `--line-buffered` и `stdbuf`

Что могут спросить следом

  • Почему tail -f log | grep x | sort ничего не выводит?
  • Чем именованный пайп (mkfifo) отличается от обычного?
  • Что будет, если читатель медленный?

Разбор

Shell вызывает pipe() и получает два дескриптора: на запись и на чтение. Потом делает fork для каждой команды, в первом процессе подменяет stdout на конец записи, во втором stdin на конец чтения, и оба выполняют exec. Команды работают параллельно, а не по очереди. Между ними буфер ядра, в Linux по умолчанию 64 КиБ. Если читатель не успевает, буфер заполняется, и писатель засыпает на write; если писать нечего, засыпает читатель. Это бесплатный backpressure. Если читатель завершился, следующая запись даёт SIGPIPE, и писатель умирает, так работает yes | head. Код конвейера по умолчанию берётся у последней команды, поэтому в скриптах включают pipefail. И ещё нюанс буферизации: когда stdout не терминал, libc копит вывод блоками, поэтому в цепочках с tail -f нужен grep --line-buffered, а sort вообще выдаёт результат только после конца ввода.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме