(c / c ++) пытается заставить EOF из родительского процесса отправлять входные данные дочернему процессу - PullRequest
4 голосов
/ 12 октября 2010

У меня есть очень простая программа на языке c / c ++, которая разветвляет дочерний процесс для выполнения другой программы, а затем отправляет некоторые данные этой дочерней программе и ожидает ответа.

дочерняя программа читает из stdinи ждет EOF, прежде чем продолжить.

Моя проблема в том, что дочерняя программа получает начальный ввод от записи канала, но никогда не видит EOF (даже если я закрываю канал), поэтому она ждет вечно.

Я не уверен, почему закрытие трубы не подразумевает EOF для stdin ребенка?

вот код:

http://gist.github.com/621210

Ответы [ 3 ]

6 голосов
/ 12 октября 2010

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

int fds[2];
pipe(fds);  // open a pipe
if (fork()) {
    // parent process
    write(fds[1], ...  // write data
    close(fds[1]); // close it
} else {
    // child process
    while (read(fds[0], ....) > 0) {
        // read until EOF

Проблема здесь в том, что конец записи канала никогда не закрывается - родительский процесс закрывает его, но дочерний процесс все еще имеет записьдескриптор открыт.Таким образом, ребенок никогда не видит EOF в дескрипторе чтения.

Самое первое, что вам нужно сделать после разветвления ребенка, - это close(fds[1]);, закрывая свою копию дескриптора записи.Таким образом, когда родитель закрывает последнюю оставшуюся ссылку на конец записи канала, дочерний элемент увидит EOF на конце чтения.

Edit

, глядя нассылка, которую вы добавили, это как раз и есть проблема - у дочернего элемента все еще есть конец записи канала, открытый на его стандартный вывод.Не дублируйте конец записи в stdout у ребенка, просто закройте его.Отправьте стандартный вывод куда-нибудь еще (файл журнала или / dev / null)

Редактировать

для двунаправленной связи, вам понадобятся два канала:

int tochild[2], fromchild[2];
pipe(tochild); pipe(fromchild);
if (fork()) {
    close(tochild[0]);
    close(fromchild[1]);
    //write to tochild[1] and read from fromchild[0]
} else {
    dup2(tochild[0], 0);
    dup2(fromchild[1], 1);
    close(tochild[0]); close(tochild[1]);
    close(fromchild[0]); close(fromchild[1]);
    exec(...
}

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

3 голосов
/ 12 октября 2010

Обновлено с тем, что я считаю проблемой: Вы читаете символ и проверяете его на предмет EOF. Это не то, как работает системный вызов read (). Он вернет 0, когда в EOF. Он не записывает EOF в буфер.

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

Полагаю, у вас здесь тоже есть распространенная ошибка. Вы не проверяете возвращаемое значение write ().

Системный вызов write не гарантирует запись всех данных перед возвратом. Может записать 4000 байт и вернуться. Он вернет количество записанных байтов. Тогда вы должны обновить указатель буфера и снова вызвать write.

Или он может вернуть код ошибки, и важно проверить это.

0 голосов
/ 06 марта 2012

Это доказательство концепции, которую я написал для вас:

Вилка Exec двойная труба Дино Чуффетти

...