Реализовать трубу в C: нужно ли разветвляться? - PullRequest
0 голосов
/ 23 сентября 2018

Я пытаюсь реализовать цепочку конвейера Linux на C. Например:

grep file | ls | wc

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

int control_flow(char** args, int precedes){

    int stdin_copy = dup(0);
    int stdout_copy = dup(1);

    // if the command and its args precedes a pipe
    if (precedes){

        int fd[2];

        if (pipe(fd) == -1){
            fprintf(stderr, "pipe failed\n");
        }

        if (dup2(fd[1], 1)!=1)
            perror("dup2 error 1 to p_in\n"); // 1 points to pipe's input

        status = turtle_execute(args); // executes the argument list, output should go into the pipe

       // Code stops running here

        if (dup2(fd[0], 0)!=0)
            perror("dup2 error 0 to p_out\n"); // 0 points to pipe's output, any process that reads next will read from the pipe

        if (dup2(stdout_copy, 1)!=1)
            perror("dup2 error 1 to stdout_copy\n"); // 1 points back to stdout

    }

    // if the command does not precede a pipe
    else{

        status = turtle_execute(args); // input to this is coming from pipe

        if (dup2(stdin_copy, 0)!=0)  // 0 points back to stdin
            perror("dup2 error 1 to stdin_copy");

    }

    return 0;
}

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

Редактировать: Это примерно то, что делает turtle_execute:

turtle_execute(args){
    if (args[0] is cd or ls or pwd or echo)
         // Implement by calling necessary syscalls
    else
         // Do fork and exec the process

Так что везде, где я использовал exec, Я впервые использовал fork, поэтому процесс замены не должен быть проблемой.

1 Ответ

0 голосов
/ 24 сентября 2018

Системный вызов exec заменяет текущий процесс выполняемой вами программой.Таким образом, ваш процесс, естественно, перестает работать после turtle_execute, поскольку он был заменен новым процессом.

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

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

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

IПредлагаем вам взглянуть на пример на странице руководства pipe (2) (http://man7.org/linux/man-pages/man2/pipe.2.html#EXAMPLE).. Здесь показан обычный способ использования канала:

  • Вызов pipe для получения команды createтруба
  • Вызывающая вилка для разветвления процесса
  • В зависимости от того, является ли это дочерним или родительским объектом, закройте один конец трубы и используйте другой

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

Я могу только догадываться, что происходит в большей части turtle_execute, но если вы выполняете разветвление, выполняете на одном процессе и ждете его на другом, не потребляя данные из канала, это может заполнить канал и поток данных.Int, где запись заблокирована.Вы должны всегда потреблять данные из канала, пока вы пишете в него.В конце концов, это труба, а не резервуар для воды.Для получения дополнительной информации загляните на справочную страницу pipe (7) в разделе «Емкость трубы».

...