2011-03-07 17 views
8

Tengo varios elementos secundarios "bifurcados" por el mismo elemento primario y trato de construir pipe conexión entre todos estos procesos secundarios como una estructura de lista vinculada . El niño 1 envía datos a child2, child 2 a child 3 .... child N a child 1. ¿Hay alguna forma adecuada de hacerlo?¿Es posible tener tubería entre dos procesos secundarios creados por el mismo elemento primario (LINUX, POSIX)

Además, si creo y me comunico entre los procesos cómo obligo al padre a "esperar" todo el proceso para terminar su trabajo desde wait() o waitpid() espera el primer proceso finalizado pero necesito esperarlos todos. Es la otra pregunta que surge.

Gracias ...

Respuesta

17

Esto es esencialmente lo que hace un depósito, si construir una cadena de redirección, es decir, algo como

ls | grep foo | sort | uniq 

Hay algunas excelentes textos introducionary sobre programación en Unix, en el que una cáscara sencilla se implementa a través del libro. Y una de las tareas de un shell es la redirección. Uno de estos libros es "Programación de aplicaciones Linux" por Michael K. Johnson y Erik W. Troan.

página del libro: http://ladweb.net/

para construir una cadena de redirecciones para N procesa necesita tubos N-1. Para cada redireccionamiento, crea un conducto utilizando la llamada al sistema pipe(int fds[2]). Después de fork() ing, pero antes de execv ing use dup2(int from, int to) para "conectar" el extremo de una tubería a la entrada estándar (0) o salida estándar de cada proceso. Aquí hay un código excesivamente simplificada, sin comprobación de errores:

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

tomar en cuenta que los índices de matriz de la tubería se han elegido de manera que reflejen los descriptores de fichero de entrada/salida estándar si se utilizan para la redirección de stdio. Esta elección no fue arbitraria.

Por supuesto se puede conectar tuberías a cualquier descriptores de archivos (por ejemplo, hay algunas aplicaciones, que esperan que sus padres se abra, dicen fd 3 y 4, conectado a las tuberías) y la mayoría de las cáscaras apoyan directamente a esto, también (por ejemplo 1 > & 3 redireccionará stdout a fd 3). Sin embargo, los índices de matriz para pipe(int fds[2]) son 0 y 1, por supuesto. Solo digo esto, porque tenía algunos estudiantes de programación de culto de carga, que sin pensar tomaron los fds de destino también para el arreglo de syscall de tubería.

Para esperar a que todos los niños terminen de usar waitpid(-1, NULL, 0) - Creo que ese es el -1 que mi pre-answerer quiso decir, lo que significa: Espere a que todos los procesos secundarios terminen. La otra opción era llamar al wait() en un bucle que devolverá el pid del hijo recién terminado. Si se llama nuevamente y aún hay un hijo en ejecución, se bloqueará nuevamente. Si no queda ningún niño, devolverá -1; Prefiero la solución waitpid.

+0

pregunta rápida, cuando uso el código anterior, mi programa se cuelga en la segunda edición, PIENSO porque está esperando un EOF para el código fuente. ¿cómo voy a cerrar el stdin? – TrewTzu

+0

@TrewTzu: No debe cerrar stdin después de haber sido reemplazado por dup2 (pipe_A [0], 0), ya que cerraría la tubería entonces. Tampoco veo por qué la empresa debería bloquear. Sin embargo, Execv no devolverá, reemplaza el proceso con el programa llamado. Es por eso que el proceso se bifurca de antemano. ¿En qué sistema operativo estás intentando esto? Solo curiosidades. – datenwolf

+0

Esto es un poco tarde, pero mirando este código, ¿no deberían los enunciados if posteriores ser "else if" en su lugar? De lo contrario, tanto el hijo como el padre del primer tenedor ejecutarán el segundo. –

2

crear todos los tubos primero, y luego desovar todos los niños con la tubería apropiada termina en FDs 0 y 1.

En cuanto a la espera, sólo seguir esperando hasta que se devuelve -1 .

+0

No consigo "solo siga esperando hasta que devuelva -1". ¿Qué quieres decir? Quieres decir solo "esperar (-1);" ¿o que? – erogol

+0

Sigue llamándolo en un bucle hasta que devuelva -1. –

3

Sí, esto es bastante fácil, sólo tiene que crear todas las tuberías de la matriz, y no olvide cerrar las tuberías/tubos de extremos en el niño (s) que no los necesita en.

Dejar FDs de las tuberías abiertas en niños que no las están utilizando es FALLO, ya que puede hacer que otros esperen por siempre para el final de la tubería.Todos los escritores deben cerrar antes de que el lector obtenga un EOF.

Cuestiones relacionadas