Tengo varios hijos “bifurcados” por el mismo padre y trato de construir pipe
conexión entre todos estos procesos secundarios como una estructura de lista enlazada. El niño 1 envía datos al niño 2, el niño 2 al niño 3…. el niño N al niño 1. ¿Hay alguna forma adecuada de hacerlo?
Además, si creo y me comunico entre procesos, cómo obligo al padre a “esperar” todo el proceso para terminar su trabajo desde wait()
o waitpid()
espera el primer proceso terminado, pero necesito esperarlos a todos. Es la otra pregunta que surge.
Gracias…
Esto es esencialmente lo que hace un shell si construye una cadena de redirección, es decir, algo como
ls | grep foo | sort | uniq
Hay algunos textos introductorios excelentes sobre la programación de Unix, en los que se implementa un shell simple a lo largo del libro. Y una de las tareas de un shell es la redirección. Uno de estos libros es “Programación de aplicaciones Linux” de Michael K. Johnson y Erik W. Troan.
La página de inicio del libro: http://ladweb.net/
Para construir una cadena de redirecciones para N procesos, necesita tuberías N-1. Para cada redirección, crea una tubería usando el pipe(int fds[2])
llamada del sistema. Después fork()
pero antes execv
uso intensivo 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 demasiado simplificado, sin verificació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(...);
}
Tenga en cuenta que los índices de matriz de la canalización se han elegido de manera que reflejen los descriptores de archivo de entrada/salida estándar si se utilizan para la redirección de stdio. Esta elección no fue arbitraria.
Por supuesto, puede conectar tuberías a cualquier descriptor de archivo (por ejemplo, hay algunas aplicaciones que esperan que se abra su padre, digamos fd 3 y 4, conectadas a tuberías) y la mayoría de los shells también admiten esto directamente (por ejemplo, 1>&3 redirigirá salida estándar en fd 3). Sin embargo, los índices de matriz para pipe(int fds[2])
son 0 y 1 por supuesto. Solo digo esto, porque tuve algunos estudiantes de programación de culto de carga, que sin pensar tomaron los fds objetivo también para la matriz de llamadas al sistema de tuberías.
Esperar a que todos los niños terminen de usar waitpid(-1, NULL, 0)
– Creo que ese es el -1 que significaba mi pre-respuesta, lo que significa: Espere a que terminen todos los procesos secundarios. La otra opción era llamar wait()
en un bucle que devolverá el pid del hijo recién terminado. Si se vuelve a llamar y todavía hay un niño corriendo, se bloqueará de nuevo. Si no queda ningún niño, devolverá -1; Prefiero el waitpid
solución.
Sí, esto es bastante fácil, solo necesita crear todas las tuberías en el elemento principal y recordar cerrar las tuberías / extremos de las tuberías en los elementos secundarios en los que no los necesita.
Dejar abiertas las FD de las cañerías en niños que no las están usando es un FALLO ya que puede hacer que los demás esperen eternamente el final de la cañería. Todos los escritores deben cerrar antes de que el lector obtenga un EOF.
Cree todas las tuberías primero, luego genere todos los elementos secundarios con los extremos de tubería apropiados en los FD 0 y 1.
En cuanto a la espera, siga esperando hasta que devuelva -1.