Реализация неограниченного количества труб в C всего с одним л oop и одной трубой - PullRequest
0 голосов
/ 17 июня 2020

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

Последовательность должна завершиться, когда закончится самый правый процесс, это: sleep 3 | sleep 3 | sleep 0 должен немедленно завершиться и не ждать ни одного из процессов сна 3.

* argvv - указатель на первый процесс (* argvv будет sleep 3, * (argvv + 1) следующий sleep 3, et c. Я не знаю, что происходит, но что-то не так с файловыми дескрипторами, и все ломается после теста.

Например, если на входе sh> ls | wc | wc, на выходе - это

sh> ls | wc | wc
sh>    1       3      25

, затем он ожидает ввода. Пока я снова не нажму Enter, он завершится. После этого sleep 3 больше не работает.

Любая помощь будет приветствоваться , большое спасибо!

Изменить:

Хорошо, я отредактировал код, и все работает нормально, кроме сна 3 | сна 0 длится 3 секунды, а не немедленно заканчивается. Я не знаю, как это исправить.

void execute(char ***argvv)
{
    pid_t pid;
    int pd[2];
    int in = 0;

    while (*argvv != NULL) {
        pipe(pd);
        
        if ((pid = fork()) < 0)
        {
            perror();
            exit(1);
        }
        else if (pid == 0) {
            dup2(in, 0);
            if (*(argvv + 1) != NULL)
                dup2(pf[1], 1);
            close(pd[0]);
            close(pd[1]);
            execvp((*argvv)[0], *argvv);
            perror();
            exit(1);
        }

        else
        {
            close(pd[1]);
            in = pd[0];

            if (*(argvv + 1) == NULL)
                close(pd[0]);
            argvv++;
        }
        wait(&pid);
    }

}

1 Ответ

1 голос
/ 17 июня 2020

Думаю, часть проблемы может заключаться в использовании wait(). Параметр pid - это ВЫХОД, сообщающий о завершении процесса fork() ed. Каждый обработанный форк заканчивается, и его необходимо wait() редактировать. Когда вы запускаете второй конвейер, все, кроме одной части предыдущего конвейера, все еще готовы для wait() редактирования.

Обычно у вас есть несколько вариантов:

  1. wait() в al oop до тех пор, пока процесс, который вы хотите завершить, не закончится.
  2. wait() в al oop до тех пор, пока не завершатся все подпроцессы.
  3. Используйте waitpid() для поиска конкретного завершение процесса.
  4. Сделайте так, чтобы только последний процесс в цепочке был дочерним по отношению к вашему процессу, сделав остальные дочерними по отношению к нему. (Это делается какой-то оболочкой, хотя я не помню какой.) Проблема в том, что она оставляет дополнительных потомков для последнего процесса в цепочке, что может сбить его с толку. процессы, и которые закончились. Когда вы создаете конвейер в фоновом режиме, это позволяет вам отображать, какие части конвейера все еще работают. (t csh делает это. bash делает половину.)
  5. fork() дважды для более ранних участников конвейера, execvp() в внуке, затем exit() в дочернем и попросите родителя wait() для ребенка закончить sh перед продолжением. Это отключает внука от родителя, поэтому его никогда не нужно ждать. 1030 *
...