Laboratorio 3 · Paso de mensajes

Línea de mecanizado con colas

Tres máquinas en cadena conectadas por colas bloqueantes: una tolva inyecta piezas, cada máquina consume de su cola de entrada y entrega a la de salida, un embalador recoge las piezas terminadas y un supervisor recibe telemetría de todas. M2 es más lenta: verás nacer el cuello de botella y propagarse la presión hacia atrás (backpressure).

Qué observar

Qué cola produce qué efecto

LíneaEfecto en la planta
hAlimentador:4 cola1.push(p)Una pieza con nº de serie entra en el sistema.
hMaquina1:3 cola1.pop()La máquina M1 recoge la pieza; se ilumina su lámpara.
hMaquina1:5 cola2.push(p)Si cola2 está llena, M1 se bloquea: la presión sube a cola1.
hMaquina2:4 mecaniza(p)M2 trabaja lentamente: es el cuello de botella.
hMaquina2:6 colaTel.push(...)El mensaje viaja a la zona del supervisor.
hSalida:3 colaSalida.pop()El contador de terminadas sube.
hSupervisor:3 colaTel.pop()Los contadores M1/M2/M3 del supervisor se actualizan.

Colas y capacidades

ColaCapacidadProductorConsumidor
cola12hAlimentadorhMaquina1
cola22hMaquina1hMaquina2
cola32hMaquina2hMaquina3
colaSalida3hMaquina3hSalida
colaTel4M1, M2, M3hSupervisor

Código C++20 equivalente

#include <jthread>

ColaBloqueante<Pieza> cola1(2), cola2(2), cola3(2), colaSalida(3);
ColaBloqueante<Msg>   colaTel(4);

struct Msg { int origen; uint32_t serie; };

void hAlimentador() {
    while (true) {
        Pieza p = nuevaPieza();
        cola1.push(p);                  // se bloquea si cola1 está llena
    }
}

void hMaquina(int n, std::stop_token st,
              ColaBloqueante<Pieza>& entrada,
              ColaBloqueante<Pieza>& salida) {
    while (!st.stop_requested()) {
        Pieza p = entrada.pop();        // se bloquea si está vacía
        mecaniza(p, n);
        salida.push(p);                 // se bloquea si está llena
        colaTel.push({n, p.serie});
    }
}

void hSalida() {
    while (true) {
        Pieza p = colaSalida.pop();
        embalar(p);
    }
}

void hSupervisor() {
    while (true) {
        Msg msg = colaTel.pop();
        registrar(msg);
    }
}

int main() {
    std::jthread alimentador(hAlimentador);
    std::jthread m1(hMaquina, 1, cola1, cola2);
    std::jthread m2(hMaquina, 2, cola2, cola3);
    std::jthread m3(hMaquina, 3, cola3, colaSalida);
    std::jthread salida(hSalida), sup(hSupervisor);
}

Nota: std::jthread no admite parámetros por referencia en hMaquina sin std::ref; en código real habría que escribirlo o pasar índices que resuelvan las colas.

Experimentos propuestos

  1. Mantén la línea en marcha hasta que la producción por tick se estabilice: ¿cuántas piezas por tick produce? Cambia mentalmente la velocidad de M2 por la de M1: ¿cambia el resultado?
  2. Observa el orden de bloqueo en el registro: cuando la línea está saturada, ¿qué hilo se bloquea primero y cuál por último? (Pista: el bloqueo empieza en el cuello de botella.)
  3. Si colaTel fuera de capacidad 1, ¿qué pasaría con M1, M2 y M3? Compara con la respuesta de la página Colas.