Czy można mieć potok między dwoma procesami potomnymi utworzonymi przez tego samego rodzica (LINUX, POSIX)


Mam kilka procesów potomnych „rozwidlonych” od tego samego rodzica i próbuję zbudować relację
pipe
pomiędzy wszystkimi tymi procesami podrzędnymi, taką jak połączona struktura listy. Dziecko 1 wysyła dane do dziecka 2, dziecko 2 do dzieci 3 .... do dziecka H w przypadku dziecka 1. Czy istnieje właściwy sposób, aby to zrobić?
Ponadto, jeśli tworzę procesy i komunikuję się między nimi, jak zmusić rodzica, aby „czekał” na zakończenie pracy całego procesu, skoro
wait ()
lub
waitpid ()
czeka na pierwszy zakończony proces, ale muszę poczekać na wszystkie. Powstaje kolejne pytanie.
Podziękować...
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zasadniczo to właśnie robi powłoka, jeśli zbudujesz łańcuch przekierowań, czyli coś w rodzaju
ls | grep foo | sort | uniq

Istnieje kilka doskonałych tekstów wprowadzających do programowania w systemie Unix, które mają prostą powłokę zaimplementowaną za pomocą książki. Jednym z zadań jest przekierowanie powłoki. Jedną z takich książek jest „41” autorstwa Michaela C. Johnsona i Erica W. Troana.
Strona główna książki:

http://ladweb.net
http://ladweb.net/
/
Aby zbudować łańcuch przekierowań dla N procesów, potrzebujesz N-1 potoków. Dla każdego przekierowania tworzysz potok przy użyciu wywołania systemowego
pipe (int fds [2])
. Po
fork ()
ing, ale przed
execv
ing użyj
dup2 (int od, int do)
- "podłącz" koniec potoku do standardowego wejścia (0 ) lub standardowe wyjście każdego procesu. Oto nadmiernie uproszczony kod, bez sprawdzania błędów:
int pipe_A[2];
int pipe_B[2];pipe(pipe_A);
pipe(pipe_B);pid_t pid_A, pid_B, pid_C;if( !(pid_A = fork()) ) {
dup2(pipe_A[1], 1);/* redirect standard output to pipe_A write end */
execv(...);
}if( !(pid_B = fork()) ) {
dup2(pipe_A[0], 0);/* redirect standard input to pipe_A read end */
dup2(pipe_B[1], 1);/* redirect standard output to pipe_B write end */
execv(...);
}if( !(pid_C = fork()) ) {
dup2(pipe_B[0], 0);/* redirect standard input to pipe_B read end */
execv(...);
}

Zauważ, że indeksy tablicy potoków zostały wybrane tak, aby odzwierciedlały standardowe deskryptory plików wejścia/wyjścia używane do przekierowania stdio. Ten wybór nie był arbitralny.
Możesz oczywiście podłączyć potoki do dowolnych deskryptorów plików (na przykład istnieją aplikacje, które oczekują, że ich rodzic otworzy, powiedzmy fd 3 i 4 podłączone do potoków), a większość powłok bezpośrednio to obsługuje (np. 1 & > & amp; 3 przekieruje standardowe wyjście do fd 3). Jednak indeksy tablicowe dla
pipe (int fds [2])
to oczywiście 0 i 1. Powtarzam to tylko dlatego, że miałem kilku studentów programowania kultowego cargo, którzy bezmyślnie brali również docelowe fds dla tablicy potoków syscall.
Aby poczekać na zakończenie wszystkich procesów podrzędnych, użyj
waitpid (-1, NULL, 0)
- myślę, że to jest -1, co miał na myśli mój pre-responder, co oznacza: czekaj na wszystkie dziecko procesy do zakończenia. Inną opcją było wywołanie
wait ()
w pętli, która zwróci pid właśnie ukończonego dziecka. Jeśli zostanie ponownie wezwany, a dziecko nadal pracuje, zostanie ponownie zablokowane. Jeśli nie ma już dziecka, zwróci -1; Wolę rozwiązanie
waitpid
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Tak, to całkiem proste, wystarczy utworzyć wszystkie rury w rodzicu i pamiętać, aby zamknąć rury/końce rur w dziecku (dzieciach), których nie potrzebujesz.
Pozostawienie otwartych FD rur dla dzieci, które ich nie używają, jest NIEUDANE, ponieważ może spowodować, że inni będą czekać wiecznie na koniec rury. Wszyscy autorzy muszą zamknąć się, zanim czytelnik otrzyma EOF.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Najpierw utwórz wszystkie rury, a następnie odradzaj wszystkich potomków z pasującymi końcami rur w FD 0 i 1.
Jeśli chodzi o czekanie, po prostu czekaj, aż zwróci -1.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się