использование EOF для передачи сигналов по безымянным каналам

У меня есть тестовая программа, которая использует безымянные каналы, созданные с помощью pipe (), для связи между родительскими и дочерними процессами, созданными с помощью fork () в системе Linux.

Обычно, когда отправляющий процесс закрывает запись fd канала, принимающий процесс возвращается из read () со значением 0, указывающим EOF.

Однако кажется, что если я заполняю канал довольно большим объемом данных (может быть, 100 Кбайт 0 до того, как получатель начнет чтение, получатель блокируется после прочтения всех данных в канале, даже если отправитель закрыл его.

Я убедился, что отправляющий процесс закрыл канал с помощью lsof, и кажется довольно очевидным, что получатель заблокирован.

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

Если да, и нет условий, которые могут привести к чтению ( ) блокировка по пустому закрытому 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 не возвращался быстро, и я оказался в тупике.

8
задан Mark Nelson 25 March 2011 в 23:26
поделиться