У меня есть тестовая программа, которая использует безымянные каналы, созданные с помощью pipe (), для связи между родительскими и дочерними процессами, созданными с помощью fork () в системе Linux.
Обычно, когда процесс отправки закрывает запись fd канала, процесс получения возвращается из read () со значением 0, указывая EOF.
Однако, похоже, что если я заполняю канал довольно большим объемом данных (может быть, 100 Кбайт0 до того, как получатель начинает читать, получатель блокирует после чтения всех данных в канале - даже если отправитель закрыл его.
Я проверил, что процесс отправки закрыл канал с помощью lsof, и кажется довольно ясным, что получатель заблокирован.
Что приводит к вопросу: является ли закрытие одного конца трубы надежным способом сообщить получателю, что данных больше нет?
Если это так, и нет условий, которые могли бы привести к блокировке read () на пустом, закрытом FIFO, что-то не так с моим кодом. Если нет, это означает, что мне нужно найти альтернативный метод сигнализации окончания потока данных.
Разрешение
Я был почти уверен, что первоначальное предположение было верным, что закрытие канала вызывает EOF на стороне читателя, этот вопрос был всего лишь выстрелом в темноте - подумав, может быть, я заметил какое-то тонкое поведение канала Почти каждый пример, который вы когда-либо видели с трубами, - это игрушка, которая посылает несколько байтов и выходит. Часто вещи работают иначе, когда вы больше не выполняете атомарные операции.
В любом случае я пытался упростить свой код, чтобы устранить проблему, и мне удалось найти мою проблему. В псевдокоде я заканчивал тем, что делал что-то вроде этого:
create pipe1
if ( !fork() ) {
close pipe1 write fd
do some stuff reading pipe1 until EOF
}
create pipe2
if ( !fork() ) {
close pipe2 write fd
do some stuff reading pipe2 until EOF
}
close pipe1 read fd
close pipe2 read fd
write data to pipe1
get completion response from child 1
close pipe1 write fd
write data to pipe2
get completion response from child 2
close pipe2 write fd
wait for children to exit
Дочерний процесс чтения pipe1 зависал, но только тогда, когда объем данных в канале стал значительным. Это происходило, хотя я закрыл канал, который читал child1.
Взгляд на источник показывает проблему. Когда я разветвлял второй дочерний процесс, он взял свою собственную копию дескрипторов файла pipe1, которые были оставлены открытыми. Даже если в канал должен записываться только один процесс, его открытие во втором процессе не позволяет ему перейти в состояние EOF.
Проблема не проявлялась с небольшими наборами данных, потому что child2 быстро заканчивал свою работу и выходил. Но с большими наборами данных child2 не возвращался быстро, и я оказался в тупике.