Нужно ли закрывать прочитанный конец ящика, чей конец записи уже закрыт?

У меня есть следующий сценарий.

  • Я создаю канал.

  • Завершился дочерний процесс.

  • Ребенок явно закрывает конец чтения и записывает в конец записи и выходит, не закрывая ничего (выход должен закрыть все дескрипторы открытых файлов/труб от имени дочернего элемента, я полагаю).

  • Родитель явно закрывает конец записи в канале и читает из считываемого конца канала, используя fgets, пока fgets не вернет NULL. т.е. он читает полностью.

Теперь мой вопрос: почему родитель должен закрывать прочитанный конец канала явно после его прочтения? Разве не разумно, чтобы система удаляла трубу вообще, как только полные данные были прочитаны из чтения?

Я закрываю конец чтения явно в родительском элементе, и у меня есть ошибка Too many file descriptors раньше или позже при открытии большего количества каналов. Мое предположение заключалось в том, что система автоматически удаляет трубку, когда ее конец записи закрыт, и данные полностью считываются с конца чтения. Потому что вы не можете из трубы дважды!

Итак, в чем смысл системы, не удаляющей трубу, когда данные были полностью прочитаны, а конец записи закрыт?

Ответ 1

Вы правы, что система закроет конец записи, когда ребенок выйдет. Однако может быть другой конец записи этого канала открытым, если дочерний fork или передает дубликат конца записи в другой процесс.

По-прежнему верно, что система сможет сказать, когда все дескрипторы на одном конце трубы были закрыты (явно или потому, что процесс владения вышел). По-прежнему не имеет смысла закрывать те, что находятся на другом конце трубы, поскольку это приведет к путанице, когда родительский процесс попытается закрыть дескриптор на своем конце трубы; либо:

  • функция fd была закрыта системой, и в этом случае возникает ошибка, когда она пытается закрыть уже закрытую fd; или
  • fd был повторно использован, что еще хуже, поскольку теперь он закрывает полностью несвязанный fd.

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

Ответ 2

Дескрипторы файлов не закрываются системой, пока процесс не завершится. Это верно для труб, а также для любого другого дескриптора файла.

Существует большая разница между каналом (или любым другим файлом) без данных в нем и закрытым файловым дескриптором.
Когда дескриптор файла закрыт, система может повторно использовать свой номер для нового дескриптора файла. Затем, когда вы читаете, вы получаете что-то еще. Поэтому после того, как вы закрыли дескриптор файла, вы больше не должны его использовать.

Теперь представьте, что как только нет больше данных, система автоматически закроет дескриптор файла. Это сделало бы номер доступным для повторного использования, и последующее несвязанное открытое может получить его. Теперь читатель, который еще не знает, что больше нет данных, будет читать из того, что, по его мнению, является каналом, но фактически будет читать из другого файла.