/ / Funkcja Pipe w powłoce Linuksa pisać w C - c, linux, shell, pipe, execvp

Funkcja Ripe w powłoce systemu Linux napisz w C - c, linux, shell, pipe, execvp

Mój program mini-shell akceptuje na przykład polecenie potoku, ls -l | wc -l i używa excevp do wykonania tych poleceń.

Moim problemem jest, jeśli nie ma fork () dla execvp, polecenie pipe działa dobrze, ale powłoka kończy się później. Jeśli istnieje fork () dla execvp, zdarza się martwa pętla. I nie mogę tego naprawić.

kod:

void run_pipe(char **args){
int ps[2];
pipe(ps);

pid_t pid = fork();
pid_t child_pid;
int child_status;

if(pid == 0){ // child process

close(1);
close(ps[0]);
dup2(ps[1], 1);

//e.g. cmd[0] = "ls", cmd[1] = "-l"
char ** cmd = split(args[index], " t");

//if fork here, program cannot continue with infinite loop somewhere
if(fork()==0){
if (execvp(cmd[0],cmd)==-1){
printf("%s: Command not found.n", args[0]);
}
}
wait(0);
}
else{ // parent process

close(0);
close(ps[1]);
dup2(ps[0],0);

//e.g. cmd[0] = "wc", cmd[1] = "-l"
char ** cmd = split(args[index+1], " t");

//if fork here, program cannot continue with infinite loop somewhere
if(fork()==0){
if (execvp(cmd[0],cmd)==-1){
printf("%s: Command not found.n", args[0]);
}
}
wait(0);
waitpid(pid, &child_status, 0);
}
}

Wiem, że fork () jest potrzebny do excevp, aby nie kończyć programu powłoki, ale wciąż nie mogę go naprawić. Każda pomoc zostanie doceniona, dziękuję!


Jak powinienem sprawić, aby dwoje dzieci było równoległych?

pid = fork();
if( pid == 0){
// child
} else{ // parent
pid1 = fork();
if(pid1 == 0){
// second child
} else // parent

}

czy to jest poprawne?

Odpowiedzi:

2 dla odpowiedzi № 1

Tak, execvp() zastępuje program, w którym jest wywoływany z innym. Jeśli chcesz odrodzić inny program bez kończenia wykonywania tego, który wykonuje odradzanie (tj. Powłokę), to ten program musi fork() aby utworzyć nowy proces, a nowy proces powinien wykonać execvp().

Twoje źródło programu wykazuje fałszywą równoległośćto prawdopodobnie myli cię lub odzwierciedla głębsze zamieszanie. Strukturyzujesz zachowanie pierwszego dziecka rozwidlonego w taki sam sposób, jak zachowanie procesu macierzystego po rozwidleniu, ale co powinien Równoległe jest zachowanie pierwszego dziecka i zachowanie drugiego dziecka.

Jednym z rezultatów jest to, że twój program ma zbyt wielewidelce. Początkowy proces powinien rozwidlać się dokładnie dwa razy - raz dla każdego dziecka, które chce się odrodzić - i żadne dziecko nie powinno się rozwidlać, ponieważ jest to już proces dedykowany jednemu z poleceń, które chcesz uruchomić. pierwsze dziecko się rozwidla, a ta sprawa jest prawdopodobnie uratowana przez dziecko wait()dla wnuka, ale jest to niechlujna i biedna forma.

Innym rezultatem jest konfiguracjadeskryptory plików drugiego dziecka, manipulujesz rodzicami, przed rozwidleniem, zamiast manipulować dzieckiem po rozwidleniu. Te zmiany utrzymają się w procesie macierzystym, co jest całkiem pewne, że nie jest to, czego chcesz. Prawdopodobnie dlatego powłoka zdaje się zawiesić: kiedy run_pipe() zwraca (standardowe wejście powłoki zostało zmienione na koniec odczytu potoku).

Ponadto proces nadrzędny powinien zostać zamknięty obie końce rury po dzieci mają obarozwidlony, mniej więcej z tego samego powodu, dla którego dzieci muszą zamknąć koniec, którego nie używają. W końcu będzie dokładnie jedna otwarta kopia deskryptora pliku dla każdego końca potoku, jeden na jednym dziecku i drugi na drugim. Nieprawidłowe wykonanie tej czynności może również spowodować zawieszenie w pewnych okolicznościach, ponieważ rozwidlone procesy mogą się nie zakończyć.

Oto podsumowanie tego, co program ma robić:

  • Oryginalny proces ustawia rurę.
  • Oryginalny proces rozwidla się dwa razy, raz dla każdego polecenia.
  • Każdy podproces manipuluje własnymi deskryptorami plików, aby użyć poprawnego końca potoku jako odpowiedniego standardowego FD i zamyka drugi koniec potoku.
  • Każdy podproces używa execvp() (lub jedną z innych funkcji w tej rodzinie), aby uruchomić żądany program
  • rodzic zamyka swoje kopie deskryptorów plików dla obu końców rury
  • rodzic używa wait() lub waitpid() zbierać dwoje dzieci.

Zauważ też, że powinieneś sprawdzić wartości zwrotne wszystkich wywołań funkcji i zapewnić odpowiednią obsługę błędów.