Volver al temario
Tema 04 · 70 páginas

Comunicación y sincronización

Tema completo Modo estudio
GUÍA DE ESTUDIO · Páginas 2934 Ver PDF

3.1.3. Paso de mensajes en Unix (colas de bytes)

Material de estudio basado en la edición de 2014. Borrador pendiente de revisión editorial independiente.

Paso de Mensajes en Unix (Colas de Bytes)

Resumen

Unix ofrece tres mecanismos de paso de mensajes indirectos, asíncronos y de tamaño variable: pipes, named pipes y sockets.

Comparación de los tres mecanismos

CaracterísticaPipesNamed PipesSockets
Crearpipe()mknod()socket()
Abrir(heredados con fork)open()bind(), listen(), accept() (servidor), connect() (cliente)
Leerread()read()read()
Escribirwrite()write()write()
Cerrarclose()close()close()
AlcanceProcesos con parentesco (padre-hijo, hermanos)Procesos con acceso al mismo directorioProcesos en máquinas diferentes

Conceptualmente, los tres son colas de bytes FIFO (first-in, first-out): productores escriben en un extremo, consumidores leen del otro.

Comportamiento especial en colas de bytes

1. Lectura sobre cola vacía:

  • Si hay file descriptors de escritura abiertos → read se bloquea hasta que haya datos.
  • Si no hay file descriptors de escritura abiertos → read devuelve 0 (fin de transmisión).

Precaución: dejar abierto innecesariamente un file descriptor de escritura puede provocar comportamientos anómalos. Conviene cerrarlos tan pronto como dejen de ser necesarios.

2. Escritura sobre cola llena:

  • El SO asigna un tamaño interno a las colas.
  • Si se supera → write se bloquea hasta que haya espacio suficiente.

3. Escritura sobre cola sin proceso consumidor:

  • El SO la considera situación anómala.
  • Envía una señal de software al proceso productor.
  • Si el productor no está preparado para tratar la señal, el SO lo hace abortar.

Diferencias con ficheros ordinarios

  • No se puede usar lseek (la gestión es estrictamente FIFO).
  • Las pipes son volátiles: al hacer shutdown, se pierde toda información no leída.

Ejemplo: pipe entre padre e hijo

int descFichero[2], n, estado;
char buf[512];

estado = pipe(descFichero);  /* Creación de la pipe */
switch(fork()) {
    case 0:  /* Hijo: lee de stdin, escribe en pipe */
        close(descFichero[0]);
        while ((n = read(0, buf, sizeof(buf))) > 0)
            write(descFichero[1], buf, n);
        close(descFichero[1]);
        break;
    default: /* Padre: lee de pipe, escribe en stdout */
        close(descFichero[1]);
        while ((n = read(descFichero[0], buf, sizeof(buf))) > 0)
            write(1, buf, n);
        close(descFichero[0]);
}

Ejemplo completo: ps aux | grep getty

El programa emula la tubería del intérprete de comandos:

  • Crea una pipe y dos procesos hijos.
  • Un hijo ejecuta ps aux (salida estándar redirigida a la pipe con dup2).
  • Otro hijo ejecuta grep getty (entrada estándar redirigida desde la pipe).
  • Los ejecutables son ajenos al uso de la pipe; funcionan con sus entradas/salidas estándar.

Errores frecuentes:

  • No cerrar los file descriptors de escritura innecesarios puede causar deadlock: el padre espera que el hijo muera, y el hijo espera que el padre cierre el canal de escritura de la pipe.

Ideas clave

  • Pipes, named pipes y sockets son colas de bytes FIFO con distintos requisitos de parentesco/ubicación.
  • Lectura de cola vacía se bloquea (si hay escritores) o devuelve 0 (si no los hay).
  • Escritura en cola llena se bloquea; escritura sin consumidor genera señal de software.
  • Las pipes son volátiles y no permiten lseek.
  • Cerrar file descriptors de escritura es esencial para evitar deadlocks.
Consultar el contenido original