Конвейеры UNIX между дочерними процессами

Я пытаюсь написать программу, которая будет порождать произвольное количество дочерних процессов и соединять их между собой, подобно конвейеру командной строки. В моем случае я пытаюсь сделать «ls -l | more» и вывести это на стандартный вывод, а затем родительский элемент продолжит выполнение других команд.

У меня есть следующий код в качестве минимального примера:

int main (int argc, const char * argv[]) {
    int fd[2];
    pipe(fd); 
    chdir("/directory/with/lots/of/files");

    // Create one child process for more
    int pid = fork();
    if (pid == 0) {
        close(fd[1]);
        int ret = dup2(fd[0],0);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "more";  argv[1] = NULL;
        execvp("more", argv);
    } 
    // Create another child process for ls
    int pid2 = fork();
    if (pid2 == 0) {
        int ret = dup2(fd[1],1);
        if (ret < 0) perror("dup2");
        char *argv[10];
        argv[0] = "ls";    argv[1] = "-l";   
        argv[2] = NULL;
        execvp("ls", argv);
    }

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}

Теперь, когда я выполняю программу (конечно, заключенную в функцию main()), я получаю больше, чем ожидалось. Я нажму «d», чтобы пролистать больше вывода, и «u», чтобы перейти вверх, и, похоже, это работает нормально. Но когда я достигаю дна, вместо того, чтобы выйти, как это делает больше, он просто оставляет пустую строку. Ctrl-C работает, чтобы выйти из него, но он закрывает всю программу, что означает «Готово!» строка никогда не печатается. Видео доступно здесь, иллюстрирующее происходящее (обратите внимание, что в самом конце я нажимаю Ctrl-C, чтобы вернуться к bash).

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


person Justin Mrkva    schedule 20.02.2011    source источник
comment
Проверьте, не является ли more символической ссылкой на less. Меньше требуется -e для выхода в конце файла. Возможно, есть разница в PATH в среде вашей программы и в вашей интерактивной среде.   -  person Dennis Williamson    schedule 21.02.2011
comment
Это не так, но спасибо за наводку. Это просто дает мне еще один тестовый пример. :)   -  person Justin Mrkva    schedule 21.02.2011


Ответы (2)


Вам нужно close() по крайней мере написать конец вашей трубы, иначе more никогда не увидит EOF. Например:

    ...

    // close parent's pipes
    close(fd[0]);
    close(fd[1]);

    // wait for the more process to finish
    int status;
    waitpid(pid, &status, 0);

    printf("Done!\n");
    return 0;
}
person Robie Basak    schedule 20.02.2011
comment
Вы также должны close(fd[0]) после dup2() в первом дочернем элементе, а также для fd[1] во втором дочернем элементе. - person caf; 21.02.2011
comment
Бинго, сработало! Я закрывал каналы в дочерних процессах (по крайней мере, в окончательной версии, я только что понял, что в минимальном примере отсутствует close(fd[0]); во втором дочернем процессе), но я никогда не думал закрывать их на стороне родителя. Посмотрев немного глубже, я нашел комментарий. После разветвления у вас будет один канал с двумя входами и двумя выходами, что имеет смысл в этом контексте. Спасибо! РЕДАКТИРОВАТЬ: Да, кафе, я заметил это, когда просматривал это, но я закрываю их в производственной версии. :) - person Justin Mrkva; 21.02.2011

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

В вашей функции wait вы ожидаете завершения первого процесса, но не ждете второго процесса. Это означает, что если второй процесс никогда не отправит EOF на выход, я думаю, ваш первый процесс не завершится.

Вы можете попробовать дождаться второго процесса вместо первого и выяснить, не в этом ли проблема.

person Tiago    schedule 20.02.2011