Pipe () z fork () z rekurencją: obsługa deskryptorów plików
Mam wątpliwości co do istniejącego pytania, które zostało zadane wczoraj:
Ponowne rekurencyjne potokowanie w Uniksie.
Ponownie publikuję problematyczny kod:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void pipeline( char * ar[], int pos, int in_fd);
void error_exit(const char*);
static int child = 0; /* whether it is a child process relative to main() */
int main(int argc, char * argv[]) {
if(argc < 2){
printf("Usage: %s option (option) ...\n", argv[0]);
exit(1);
}
pipeline(argv, 1, STDIN_FILENO);
return 0;
}
void error_exit(const char *kom){
perror(kom);
(child ? _exit : exit)(EXIT_FAILURE);
}
void pipeline(char *ar[], int pos, int in_fd){
if(ar[pos+1] == NULL){ /*last command */
if(in_fd != STDIN_FILENO){
if(dup2(in_fd, STDIN_FILENO) != -1)
close(in_fd); /*successfully redirected*/
else error_exit("dup2");
}
execlp(ar[pos], ar[pos], NULL);
error_exit("execlp last");
}
else{
int fd[2];
pid_t childpid;
if ((pipe(fd) == -1) || ((childpid = fork()) == -1)) {
error_exit("Failed to setup pipeline");
}
if (childpid == 0){ /* child executes current command */
child = 1;
close(fd[0]);
if (dup2(in_fd, STDIN_FILENO) == -1) /*read from in_fd */
perror("Failed to redirect stdin");
if (dup2(fd[1], STDOUT_FILENO) == -1) /*write to fd[1]*/
perror("Failed to redirect stdout");
else if ((close(fd[1]) == -1) || (close(in_fd) == - 1))
perror("Failed to close extra pipe descriptors");
else {
execlp(ar[pos], ar[pos], NULL);
error_exit("Failed to execlp");
}
}
close(fd[1]); /* parent executes the rest of commands */
close(in_fd);
pipeline(ar, pos+1, fd[0]);
}
}
Wystąpił błąd:
Example:
./prog ls uniq sort head
gives:
sort: stat failed: -: Bad file descriptor
Zaproponowane rozwiązanie brzmiało: „nie zamykaj deskryptorów plików fd [1] i in_fd w procesie potomnym, ponieważ są one już zamknięte w procesie macierzystym.”
My Confusion: (przepraszam, jestem nowicjuszem w Linuksie)
Zgodnie z moją książką „Rozpoczęcie programowania w Linuksie”, kiedy rozwidlamy () proces, deskryptory plików są również duplikowane. Dlatego rodzic i dziecko powinni mieć różne deskryptory plików. Jest to sprzeczne z odpowiedzią.
Moja próba:
Sam próbowałem uruchomić ten kod i zobaczyłem, że problem pojawia się tylko wtedy, gdy zamknę deskryptor pliku „in_fd” w obu procesach (rodzic i potomek). Nie zależy od fd [1].
Co ciekawe, jeśli spróbuję./prog ls sort head
działa dobrze, ale kiedy próbuję./prog ls sort head uniq
daje błąd odczytuhead
.
Moje myśli: Thein_fd
deskryptor pliku jest tylko zmienną wejściową int dla tej funkcji. Wydaje się, że nawet po rozwidleniu pozostaje tylko jeden deskryptor pliku, który jest współdzielony zarówno przez rodzica, jak i dziecko. Ale nie jestem w stanie zrozumieć, jak.