Что заставляет процесс Unix умирать с Broken pipe?

30

Вот несколько вариантов, о которых я подумал, но не уверен, что это правильный вариант.

  1. Произошла ошибка чтения ввода-вывода из канала.
  2. Запись процесса на другой конец канала завершилась сбоем.
  3. Все процессы, которые могли писать в канал, закрыли его.
  4. Буфер записи канала заполнен.
  5. Пир закрыл другое направление дуплексной трубы.
  6. Запись не удалась, потому что нет процессов, которые могли бы читать из канала.
  7. Системный вызов вернул ошибку EPIPE, и обработчик ошибок не был установлен.
siamii
источник
Каков твой вопрос? Вы спрашиваете, что из этого является правильным, или есть какие-то другие вещи, которые могут привести к поломке трубы?
EightBitTony
@EightBitTony Что из этого верно
Сиами

Ответы:

38

Процесс получает SIGPIPE, когда он пытается выполнить запись в канал (именованный или нет) или сокет типа SOCK_STREAM, у которого нет считывателя.

Это вообще желаемое поведение. Типичный пример:

find . | head -n 1

Вы не хотите findпродолжать работать после того, headкак завершили работу (а затем закрыли единственный файловый дескриптор, открытый для чтения по этому каналу).

Команда yesобычно полагается на этот сигнал для завершения.

yes | some-command

Будет писать «y», пока не завершится какая-либо команда.

Обратите внимание, что это происходит не только при выходе из команд, но и тогда, когда все читатели закрыли чтение fd для канала. В:

yes | ( sleep 1; exec <&-; ps -fC yes)
      1 2       1        0

Будет 1 (подоболочка), затем 2 (подоболочка + сон), затем 1 (подоболочка), затем 0 fd, считывающих из канала после того, как подоболочка явно закроет свой стандартный ввод, и именно тогда yesполучит SIGPIPE.

Выше, большинство оболочек использовать в pipe(2)то время как ksh93использует socketpair(2), но поведение такое же в этом отношении.

Когда процесс игнорирует SIGPIPE, запись системного вызова ( как правило write, но может быть pwrite, send, splice...) возвращается с EPIPEошибкой. Таким образом, процессы, желающие обработать сломанный канал вручную, обычно игнорируют SIGPIPE и предпринимают действия при ошибке EPIPE.

Стефан Шазелас
источник
14

(6)

Запись не удалась, потому что нет процессов, которые могли бы читать из канала.

Хотя до тех пор, пока вы не продублируете дескрипторы и разветвление, может быть запущен только один процесс: обычно в канале есть один читатель и один писатель, и когда один из них закрывает соединение, канал не функционирует. Если вы используете именованный канал, вы можете создать с ним несколько соединений (последовательно), но каждый из них представляет новый канал в этом смысле. Таким образом, «канал» к потоку или процессу является синонимом дескриптора файла.

От man 7 pipe:

Если все файловые дескрипторы, относящиеся к концу чтения канала, были закрыты, то запись (2) приведет к генерации сигнала SIGPIPE для вызывающего процесса. Если вызывающий процесс игнорирует этот сигнал, то write (2) завершается с ошибкой EPIPE.

Таким образом, «сломанная труба» для писателя - то же самое, что EOF для читателя.

лютик золотистый
источник
0

Сломанный канал возникает, когда процесс чтения завершается до процесса записи. Так что я бы пошел с (6)

SidJ
источник
2
Может быть несколько процессов чтения или записи в канал, и один и тот же процесс может быть чтение и запись. Кроме того, речь идет не о выходе, а о закрытии файлового дескриптора.
Стефан Шазелас