Постоянный execvp на трубе? - PullRequest
       14

Постоянный execvp на трубе?

3 голосов
/ 15 ноября 2011

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

Моя мини-оболочка должна принимать две команды, например ls | grep a. Для этого я создаю трубу второго размера и ребенка. Ребенок закрывает все, что он должен закрыть, и открывает все, что он должен открыть (стандарт / труба входит и выходит). Затем он выполняет «ls», используя execvp. Я уверен, что это работает хорошо. После этого родитель закрывает и открывает входы и выходы (я уверен, что я делаю это хорошо), а затем выполняет grep a.

Теперь проблема в том, что процесс grep a никогда не заканчивается. То же самое для tail -1, например. Но оно работает для head -1. Я думаю, что это происходит потому, что grep и tail, которые выполняются родителем, ожидают большего ввода, даже если дочерний процесс завершил свою работу. ls | grep a производит правильный вывод, отображаемый на консоли (вывод канала устанавливается как вывод по умолчанию), но, как я уже сказал, grep a не завершается.

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

Спасибо.

Вот код:

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

   int fd[2];
   pipe(fd);

   if ((pid = fork()) != -1){ 
     if(pid == 0){         /*Child executing */
        close(fd[0]);
        close(1);
        dup(fd[1]);
        close(fd[1]);
        execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */

      } else{             /* Parent executing */
        wait(&status);
        close(fd[1]);
        close(0);
        dup(fd[0]); 
        close(fd[0]);
        execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
       }
   }  

1 Ответ

9 голосов
/ 15 ноября 2011

Если grep продолжает работать после выхода из ls, это означает, что вы не закрыли все трубы, которые вам нужно закрыть.

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


Вставленный код работает правильно (при расширении до полной программы, как показано ниже). Оба подпроцесса работают нормально.

Это означает, что вы устранили код, в котором возникла проблема, когда вы создали здесь урезанную версию - возможно, у вас есть еще один fork() между вызовом pipe() и этим fork()?

#include <unistd.h>
#include <sys/wait.h>

int main()
{
   pid_t pid;
   char *argvv[2][3] = { { "ls", 0, 0}, { "grep", "a", 0 } };
   int status;

   int fd[2];
   pipe(fd);

   if ((pid = fork()) != -1) {
     if(pid == 0){         /*Child executing */
        close(fd[0]);
        close(1);
        dup(fd[1]);
        close(fd[1]);
        execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */

      } else{             /* Parent executing */
        wait(&status);
        close(fd[1]);
        close(0);
        dup(fd[0]);
        close(fd[0]);
        execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
       }
   }

   return 0;
}
...