2014-05-16 4 views
0

Я создаю службу TCP, которая разворачивает новый процесс каждый раз, когда клиент подключается. Перед вилкой я настраивал трубу, чтобы ребенок мог отправлять статистику, собранную во время соединения, обратно родителям. Родитель закрывает конец записи, а дочерний элемент закрывает конец чтения, а родитель поддерживает массив дескрипторов файлов для чтения, по одному на каждого ребенка.Как родительский дескриптор файла pipe закрывается при выходе дочернего процесса

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

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

В общем, что должен сделать родительский процесс с дескриптором файла трубы при выходе из него?

ответ

3

В вашем случае родительский процесс должен закрыть конец записи прямо после вилки. Затем он может читать свои статистические данные до EOF (конец файла), а затем закрывать конец считывания.

+0

Я уже закрыл конец записи в родительском и читающем конце в дочернем. Вы говорите, что родительский 'read' будет сообщать EOF, когда ребенок вышел, и я могу его обнаружить таким образом? – Flash

+2

Да; если ребенок умирает, 'read()' на трубе вернет 0, указывающий EOF. Если конец записи трубы открыт, считывание будет зависать до тех пор, пока не будут прочитаны данные или конец записи трубки закрыт. –

+0

@Andrew: способ думать о файловом дескрипторе является указателем, отсчитываемым от ссылки, на уровень. 'dup2' копирует указатель, а' close' сбрасывает его. После того, как написание текста исчезло (потому что оно больше не упоминается), чтение с конца чтения вернет EOF. – tmyklebu

0

broken pipe происходит, когда вы пишете на трубу, но нет fd для чтения с этой трубы. Так что это не относится к вашему делу. В вашем случае, так как ваш родитель читает из канала, он должен читать EOF, когда ребенок завершает работу (если вы закрыли конец записи в родительском процессе правильно, иначе он будет просто заблокирован, так как предполагается, что все еще будут читать вещи будущее). Затем вы можете безопасно закрыть чтение fd в своем родительском процессе.

В общем

Если родитель пишет и читает ребенок, вам не нужно беспокоиться о broken pipe, который, когда ребенок закрывает чтения FD, и родитель получает SIGPIPE как он продолжает писать к трубе. SIGPIPE по умолчанию завершает процесс, поэтому вы можете настроить обработчик сигнала, чтобы он делал все, что вам нужно (если вы не хотите, чтобы он просто заканчивался).

3

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

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

Альтернативный механизм использует select() или poll() или связанную функцию, которая сообщает, что операция чтения в файловом дескрипторе не зависает. Когда он обнаруживает EOF (чтение нулевых байтов) из канала, он знает, что ребенок умер. Тем не менее, это, вероятно, смутно.

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

Второй проход: после получения дополнительной информации.

Если вы уже используете select() в цикле, а затем, когда ребенок умирает, вы получите «трубу готовый для чтения» указание от select() и вы получите 0 байт от read() который указывает EOF на этой трубе. Затем вы должны закрыть эту трубу (и подождать одного или нескольких детей с waitpid(), возможно, используя W_NOHANG - должен быть хотя бы один труп, который нужно собрать - так что у вас не будет зомби, которые будут ногами в течение длительных времен).

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

+0

Существует поток сообщений, поэтому мне понадобится цикл select в родительском, чтобы выбрать между всеми трубами, а также прослушивающим сокетом. Если 'select' сообщает мне, что канал готов для чтения, а' read' возвращает 0 (EOF), я должен иметь возможность просто закрыть трубу на родительском конце, не так ли? – Flash

+0

Да; если вы уже используете 'select()', то вы получите «готовность к чтению», а затем EOF (чтение 0 байт), и вы можете закрыть этот канал (и дождаться ребенка) - там должен быть труп которые будут собраны, чтобы у вас не было зомби, носящих длительное время). –

+0

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

Смежные вопросы