Patrones clásicos

Productor–consumidor

El patrón que aparece en cada junta de una planta: una estación produce, la siguiente consume, y entre medias un buffer de capacidad finita. Se gobierna con dos semáforos (huecos y elementos) y, si el buffer es una estructura compartida, un mutex.

La instalación en acción

Un horno de cocción separa la preparación del enfriado: pulsa Ejecutar y observa cómo la carga se bloquea cuando el horno está lleno y la descarga cuando está vacío, y cómo el mutex protege la cola del horno.

Consejo: usa ⏭ Paso para ver qué línea de cada hilo se ejecuta y por qué.

El problema

Solución con semáforos (estilo clásico)

constexpr int N = 5;                       // capacidad del buffer

Semaforo sHuecos(N);                       // N huecos libres al empezar
Semaforo sElementos(0);                    // ningún elemento al empezar
Semaforo sMutex(1);                        // protege el buffer
std::queue<Pieza> buffer;

void hProductor() {
    while (true) {
        Pieza p = fabricar();
        sHuecos.wait();                    // espera hueco
        sMutex.wait();                     // región crítica
        buffer.push(p);
        sMutex.signal();
        sElementos.signal();               // un elemento disponible
    }
}

void hConsumidor() {
    while (true) {
        sElementos.wait();                 // espera elemento
        sMutex.wait();                     // región crítica
        Pieza p = buffer.front();
        buffer.pop();
        sMutex.signal();
        sHuecos.signal();                  // un hueco liberado
        procesar(p);
    }
}
⚠ Orden de los wait

El productor espera primero el hueco y luego el mutex, nunca al revés. Si tomara el mutex y luego esperara hueco dentro de la región crítica, el consumidor jamás podría entrar a vaciar: interbloqueo. Esta es la causa número uno de deadlock en buffers.

Solución moderna con cola bloqueante

Con la clase ColaBloqueante de la sección Colas, los tres semáforos quedan encapsulados y el código de estación se reduce a push/pop:

ColaBloqueante<Pieza> buffer(N);

void hProductor() {
    while (true) buffer.push(fabricar());     // bloquea si llena
}
void hConsumidor() {
    while (true) procesar(buffer.pop());      // bloquea si vacía
}

Varios productores, varios consumidores

El patrón escala sin cambios: cualquier número de hilos puede hacer push y pop de la misma cola, porque la propia cola serializa el acceso. Ejemplo típico: varias cintas de entrada alimentan un pulmón común del que tiran varios robots.

Interpretación física

Concepto del patrónEn la instalación
BufferPulmón, almacén intermedio, tramo de cinta, mesa de transferencia.
Capacidad NNúmero de posiciones físicas reales.
Productor bloqueadoEstación aguas arriba parada porque no hay dónde dejar.
Consumidor bloqueadoEstación aguas abajo en espera de material (hambre de pieza).
Ocupación mediaIndicador de equilibrio de la línea (KPI del laboratorio).
💡 Laboratorio

La línea de envasado implementa exactamente este patrón: observa los semáforos sHuecos, sBotellas y sMutex mientras la llenadora y la empaquetadora van a ritmos distintos.