È ansible avere pipe tra due processi figli creati dallo stesso genitore (LINUX, POSIX)

Ho figli multipli “biforcuti” dallo stesso genitore e cerco di build pipe connessione tra tutti questi processi figli come una struttura di liste collegate. Child 1 invia i dati a child2, child 2 a child 3 …. child N a child 1. Esiste un modo corretto per farlo?

Inoltre, se creo e comunico tra processi, costringo il genitore ad “attendere” tutto il processo per terminare il proprio lavoro dal momento che wait() o waitpid() attende il primo processo finito ma devo attendere tutti. È l’altra domanda che sorge.

Grazie…

Questo è essenzialmente ciò che fa una shell se costruisce una catena di reindirizzamento, cioè qualcosa di simile

 ls | grep foo | sort | uniq 

Ci sono alcuni eccellenti testi introduttivi sulla programmazione Unix, in cui una semplice shell è implementata attraverso il libro. E uno dei compiti di una shell è il reindirizzamento. Uno di questi libri è “Linux Application Programming” di Michael K. Johnson e Erik W. Troan.

L’homepage del libro: http://ladweb.net/

Per build una catena di reindirizzamenti per i processi N sono necessari i tubi N-1. Per ogni reindirizzamento crei una pipe usando la chiamata di sistema pipe(int fds[2]) . Dopo fork() , ma prima di execv dup2(int from, int to) per “connettere” l’estremità di un tubo allo standard input (0) o allo standard output di ogni processo. Ecco un codice troppo semplificato, senza controllo degli errori:

 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(...); } 

Prendi nota del fatto che gli indici di array della pipe sono stati scelti in modo da riflettere i descrittori di file di input / output standard se vengono utilizzati per il reindirizzamento stdio. Questa scelta non era arbitraria.

Naturalmente puoi colbind pipe a qualsiasi descrittore di file (es. Ci sono alcune applicazioni, che si aspettano l’apertura del genitore, ad esempio fd 3 e 4, collegate a pipe) e la maggior parte delle shell supporta direttamente anche questo (ad esempio 1> & 3 reindirizzerà stdout in fd 3). Tuttavia gli indici di array per pipe(int fds[2]) sono ovviamente 0 e 1. Lo sto dicendo, perché ho avuto alcuni studenti di programmazione settoriale per il carico, che hanno preso irrimediabilmente il target fds anche per l’array pipe syscall.

Aspettare che tutti i bambini finiscano di usare waitpid(-1, NULL, 0) – Penso che sia il -1 che significava il mio pre-responsabile, il che significa: Aspetta che tutti i processi figli finiscano. L’altra opzione stava chiamando wait() in un ciclo che restituirà il pid del figlio appena terminato. Se chiamato di nuovo e c’è ancora un bambino in esecuzione, si bloccherà di nuovo. Se non ci sono figli rimasti, restituirà -1; Preferisco la soluzione waitpid .

Sì, questo è abbastanza facile, devi solo creare tutti i tubi nel genitore, e ricorda di chiudere i tubi / estremità dei tubi nel bambino (i) che non ti servono.

Lasciare FD dei tubi aperti nei bambini che non li usano è un FAIL in quanto può far aspettare gli altri per sempre la fine del tubo. Tutti gli scrittori devono chiudere prima che il lettore ottenga un EOF.

Crea prima tutti i tubi, quindi genera tutti i bambini con le estremità del tubo appropriate negli FD 0 e 1.

Per quanto riguarda l’attesa, continua ad aspettare finché non ritorna -1.