¿Es posible tener una tubería entre dos procesos secundarios creados por el mismo padre (LINUX, POSIX)?

5 minutos de lectura

avatar de usuario
erogol

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 execvuso 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.

  • pregunta rápida, cuando uso el código anterior, mi programa se cuelga en el segundo execv, PIENSO porque está esperando un EOF para el stdin. ¿Cómo estoy destinado a cerrar el stdin?

    – Trew Tzu

    4 de septiembre de 2011 a las 5:22

  • @TrewTzu: no debe cerrar stdin después de que se haya reemplazado con dup2 (pipe_A[0], 0), ya que entonces cerraría la tubería. Tampoco veo por qué execv debería bloquear. Sin embargo, execv no regresará, 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

    4 de septiembre de 2011 a las 9:13

  • Esto es un poco tarde, pero mirando este código, ¿no deberían ser las declaraciones if subsiguientes “else if” en su lugar? De lo contrario, tanto el hijo como el padre de la primera bifurcación ejecutarán la segunda.

    –Jacob Sharf

    23 de abril de 2013 a las 18:05

  • @JacobSharf: No, porque exec… reemplaza la imagen del proceso. Todo después de la exec… dentro de la instrucción if no se ejecuta.

    – datenwolf

    23 de abril de 2013 a las 19:05

  • El enlace al libro está roto, puedes acceder a él a través de archive.org/details/linuxapplication0000john/page/n583/mode/2up

    – cassepipe

    4 de enero a las 11:03

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.

avatar de usuario
Ignacio Vázquez-Abrams

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.

  • No entiendo “simplemente sigue esperando hasta que devuelva -1”. ¿Qué quieres decir? Quiere decir simplemente “esperar (-1);” ¿o que?

    – erogol

    7 de marzo de 2011 a las 22:20

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

    – Ignacio Vázquez-Abrams

    7 de marzo de 2011 a las 22:25

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad