No es un bug, es una característica no documentada

miércoles, 30 de septiembre de 2015

Servicios y procesos. Procesos en C (II). PIPE

PIPE

Las PIPE (tuberías) son un mecanismo para poner en comunicación los procesos padre e hijo.
Se comporta como un falso fichero en el que ambos pueden leer y escribir.

Conceptualmente hablando, tendremos dos procesos, padre e hijo. Entre ellos se creará una tubería que emplearán para leer y escribir.
Para ello usaremos un array de enteros de dos posiciones. El [0] será de lectura, y el [1] de escritura. Es bidireccional pero sólo puede usarse en uno de los dos sentidos.

Si necesitamos una comunicación que circule en los dos sentidos, habrá que crear dos PIPE, uno para cada dirección.

Para poder utilizar este método de comunicación deberemos cargar la librería unistd, y tener en cuenta que se escribe como los ficheros, usando la función write y read.

Veamos un código de ejemplo para pillar la idea.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){

     int fd[2];
     char buffer[30];
     pid_t pid;

     //#include<unistd.h>
     // int pipe(int fd[2]);
     // fd[0] contiene el descriptor para lectura

     pipe(fd); // Se crea el PIPE
     pid = fork();

     switch(pid){
     
          case -1: // Error
                printf("No se ha podido crear un hijo \n");
                exit(-1);
                break;
          case 0: // Hijo
                close(fd[0]); // Cierra el descriptor que no va a usar. El de lectura
                printf("El hijo escribe en el PIPE... \n");
                write(fd[1], "Hola papi", 10);
                break;
          default: // Padre
                close(fd[1]); // Cierra el descriptor de escritura
                wait(NULL); // Espera a que finalice el hijo
                printf("El padre lee el PIPE \n");
                read(fd[0], buffer, 10);
                printf("\t Mensaje leido: %s \n", buffer);
     }
}
En el código podemos ver que después de la declaración de cada proceso, tenemos una lína que reza:
close(fd[1]);
Con esto lo que hacemos es cerrar la parte de la tubería que no vamos a utilizar. Me explico, si el que escribe es el hijo, en su lado cerraremos la posición cero, y si el padre es el que va a leer, cerraremos la posición 1. Así conseguiremos algo más de seguridad en nuestro programa. Es una práctica recomendable, aunque es verdad que nuestro código funcionará exactamente igual sin hacerlo.

Ejercicio. Haz tres procesos (padre, hijo y nieto) que se comuniquen entre ellos a través de PIPEs.

Solución.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){

     int fd1[2], fd2[2];
     char buffer[30], buffer2[30];

     pid_t pid, pidNieto;

     pipe(fd1);
     pipe(fd2);

     pid = fork();

     switch(pid){

          case -1: // Error
                printf("Ha habido un error \n");
                exit(-1);
                break;
          case 0: // Hijo
                close(fd1[0]);
                printf("Escribe el padre: \n");
                write(fd1[1], "El padre dice hola", 20);

                //Creación de nieto
                pidNieto = fork();

                switch(pidNieto){
                     case -1: // Error
                          printf("Ha habido un error \n");
                          exit(-1);
                          break;
                     case 0:
                          close(fd2[0]);
                          printf("Escribe el nieto \n");
                          write(fd2[1], "Soy el nieto", 13);
                          break;
                     default:
                          close(fd2[1]);
                          wait(NULL);
                          printf("El padre lee \n");
                          read(fd2[0], buffer2, 13);
                          printf("Mensaje leído: %s", buffer2);
                          break;
                }
                break;
          default: // Padre
                close(fd1[1]);
                wait(NULL); // Espero que finalice el nieto
                printf("\nEl abuelo lee: \n");
                read(fd1[0], buffer, 20);
                printf("Mensaje leído: %s \n", buffer);
                break;
     }

}

0 comentarios:

Publicar un comentario