Comunicación Entre Procesos
(Interprocess Communication, IPC)

En esta sección estudiaremos Pipes, FIFOs,  colas de mensajes (menos relevantes), semáforos,  memoria compartida, y UNIX-domain sockets.

Pipes
Una pipe provee una interfaz entre dos procesos.
Es un par de descriptores especiales que, en lugar de conectar a un archivo, conecta a otro proceso.
Una pipe provee un canal de comunicación unidireccional entre dos procesos que cooperan.

Pipes

Por ejemplo: considere la siguente secuencia,
    % ps -ef   > out1
    % fgrep netscape out1 > out2
    % fgrep -v agv out 2 > out3
    % lp out3
    % rm out1 out2 out3

fgrep fue escrito como un filtro; es decir, puede leer desde la entrada estándar o archivo y escribe en la salida estándar. Estos programas pueden ser unidos a través de pipes por el shell.
    % ps -ef | fgrep netscape | fgrep -v agv | lp

La herramienta usada para conectar estos programas es una pipe.

Creación de pipes

    Hay dos formas para crear una pipe entre dos procesos: popen()  y  pipe()
    La forma más simple es a través de la función popen.

    #include <stdio.h>
    FILE *popen (const char * command, const char *type),

    Esta función crea una pipe para leer desde o escribir a otro comando. El comando se pasa como argumento. Type puede ser "r" o "w".
    Este función crea un nuevo proceso y ejecuta el comando. Luego crea una pipe desde la entrada o salida estándar de este proceso dependiendo de si se abrió para escritura o lectura.

    Para cerrar la pipe use:
    #include <stdio.h>
    int pclose(FILE * stream);

Esta función ejecuta un waitpid para esperar por el término del comando y su código de término.

Ejemplo: Impresión de los dias de la semana con popen .

Precauciones:

  1. popen no es tan eficiente cuando se compara con los llamados al sistema. Memoria compartida es mejor en otros casos. (ver tarea año 2000 icd326).
  2. Llamados al sistema son siempre más eficientes. Ver time() y localtime() en este caso.
  3. No usar popen en programas con permiso de superusuario. Existe el riesgo que el comando a ejecutar sea cambiado.


Uso más avanzado de pipe  (Ver también material aportado por César León , 2s2005)
    Una pipe puede ser creada con la función pipe
    #include <unistd.h>
    int pipe (int f [2]);

    Se crean dos descriptores de archivo, uno para lectura f [0] y otro para escritura f [1].
Lo que se escribe por fd[1] se puede leer por fd[0].

Condiciones especiales:

  1. Si el extremo escritor cierra la pipe, el lector puede continuar hasta que los datos terminan y luego recibe end-of-file.
  2. Si el extremo lector cierra la pipe, un intento por escribir en la pipe genera la señal SIGPIPE.
Ejemplo: Dias de la semana con pipe .

Paréntesis: función dup2
    #include <unistd.h>
    int dup (int fd);
    int dup2(int fd, int fd2);

    dup retorna un nuevo descriptor de archivo que referencia el mismo archivo que fd.
    dup2 causa que el descriptor de archivo fd2 se refiera al mismo descriptor que fd.

Otros ejemplos de uso de pipe: Programa para enviar mail (Requiere comando mail soportado) . Programa para jugar con gnupot.

FIFOs
    Una limitación de pipes es que sólo se pueden usar entre procesos relacionados (padre-hijo etc).
FIFOs estan relacionadas con una entrada en el sistema de archivo y así pueden ser usadas por procesos no relacionados (pero deben tener acceso al mismo archivo).
Las FIFOs son un tipo especial de archivo. la creación de un FIFO es similar a la creación de un archivo.

Cración de FIFOs
    #include <sys/types.h>
    #include <sys/stat.h>

    int mkfifo (const char *path, mode_t mode);

path es el nombre de la FIFO a ser creada en el sistema de archivo, la cual no debe existir previamente.
mode contiene los permisos de la FIFO, es similar a su uso en la función open().

Escrituras sobre una FIFO que no tiene proceso lector genera una señal SIGPIPE.

Ejemplo: mkfifo también existe como comando de consola. En este caso supongamos que deseamos procesar la salida de un programa de dos formas, cada una con un programa distinto. Podemos usar el comando tee para duplicar el contenido de la salida estandar en un archivo, que en lugar de irse a disco será una FIFO.
% mkfifo fifo1
% prog3 < fifo1 &
% prog1 < infile | tee fifo1 | prog2

prog3 quedara esperando en background por datos desde fifo1.
prog1 lee infile, lo procesa y su salida es duplicada por tee hacia la entrada de fifo1 y la salida estándar que es conducida a prog2.
Sin hace uso de archivos emporales hemos podido enviar la salida de prog1 a prog2 y prog3.

Ejemplo de uso pasando información de una proceso a otro. Servidor / cliente

Sockets del Dominio UNIX (UNIX-Domain Sockets)
    Son similares a las FIFO. La dirección es dada por un archivo en el sistema de archivo.
    Su principal diferencia con FIFO es la manera como la comunicación es generada. En este caso se sigue un procedimiento similar al seguido para establecer comunicación entre procesos remotos (fuera de la máquina). Esta forma de comunicación entre procesos la veremos cuando se vea comunicación entre procesos remotos.