Чтение из трубы для моего дочернего процесса - PullRequest
1 голос
/ 03 декабря 2010

Надеюсь, простой вопрос. Я пытаюсь изучить одновременно fork (), pipe () и waitpid () и сталкиваюсь с некоторыми проблемами.

if (pipe(myout)<0 || pipe(myin)<0 || pipe(myerr)<0) { perror("Couldn't make pipes"); return; }
int childpid=fork();
if (childpid==0) { //child
    fdopen(myout[1], "w");
    fdopen(myin[1], "r");
    fdopen(myerr[1], "w");
    dup2(myout[1],  1);
    dup2(myin[1], 0);
    dup2(myerr[1], 2);
    printf("This should be seen\n");
    fclose(stdout); fclose(stdin); fclose(stderr);
    sleep(10);
    _exit(0);
 } else { //parent, wait on child
    printf("parent, monitoring\n");
    sim_out=fdopen(myout[0], "r");
    sim_in=fdopen(myin[0], "w");
    sim_err=fdopen(myerr[0], "r");
    printf("have my fds\n");
    int status;
    do {
        int ch;
        if (read(myout[0], &ch, 1)>0)
            write(1, &ch, 1);
        else printf("no go\n");
            waitpid(childpid, &status, WNOHANG);
    } while (!WIFEXITED(status) && !WIFSIGNALED(status));
}

Я получаю:

родитель, мониторинг есть мои FDS T

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

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

Где я не прав?

Ответы [ 2 ]

5 голосов
/ 03 декабря 2010

Я думаю, что вижу несколько проблем. Я постараюсь упомянуть их в порядке появления.

  • Вам следует проверить fork для возвращаемого значения -1, которое указывает на ошибку (в этом случае ни один ребенок не будет разветвлен).
  • Все ваши вызовы fdopen дают утечку ресурсов (в зависимости от реализации; утечка по RHEL4). Они возвращают FILE*, который вы могли бы затем использовать в fwrite и т. Д., А затем закрываете, выполняя fclose над ними. Но вы выбрасываете это значение. Вам не нужно открывать канал для чтения / записи. Трубы подходят для этого при создании.
  • Ребенок должен закрыть концы трубы, которую он не использует. Добавить close (myin [1]); myin [1] = -1; close (myout [0]); myout [0] = -1; close (myerr [0]); myerr [0] = -1;
  • dup2 технически подходит для всех известных мне вариантов Linux, но обычно используется первый fd канала для чтения, а другой - для записи. Таким образом, ваши dup2 лучше всего изменить на dup2 (myin [0], STDIN_FILENO); dup2 (myout [1], STDOUT_FILENO); dup2 (myerr [1], STDERR_FILENO);
  • Родитель должен закрыть концы неиспользуемой трубы. Добавить close (myin [0]); myin [0] = -1; close (myout [1]); myout [1] = -1; close (myerr [1]); myerr [1] = -1;
  • Ваша основная проблема: Вы проверяете возможно неинициализированный status для кода выхода вашего ребенка. Но waitpid еще не было названо. Вы должны проверить код выхода waitpid и не оценивать status, если он возвращает что-то отличное от childpid.

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

Поскольку теперь открыты только те концы труб, которые вам действительно нужны, операционная система обнаружит для вас сломанную трубу. Труба разрывается, когда ребенок делает fclose (stdout). Родитель по-прежнему может читать все данные, которые могут находиться в канале, но после этого read вернет ноль, указывая на сломанный канал.

Таким образом, вы можете сэкономить вызов waitpid. Вместо этого вы можете просто подождать, пока read вернет ноль. Это не на 100% эквивалентно, так как ваш дочерний элемент закрывает свой конец канала до того, как он перейдет к sleep (в результате чего родительский процесс продолжится, когда все данные будут прочитаны), тогда как версия waitpid, конечно, только продолжается, когда ребенок действительно умер.

0 голосов
/ 03 декабря 2010

Кто-то ответил на это ... Я не знаю, что с этим случилось.Учитывая, что я новичок здесь, может быть, я как-то удалил это?Если так, я прошу прощения, но у них был ответ.

Решение состоит в том, чтобы не использовать макросы WIF *, если только waitpid ()> 0, поскольку, очевидно, в противном случае 0 считается нормальным выходом.Я вставил в свой код чек, и теперь он работает - спасибо всем за указатели редактирования.

...