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
- La cola
cola2(entrada de M2) se llena yhMaquina1queda bloqueado encola2.push: la presión sube aguas arriba. - Cuando
cola1también se llena, se bloquea hasta la propia tolva (hAlimentador): la línea se autorregula sola. - El supervisor consume la
colaTelsin ralentizar a nadie: lectura de datos sin compartir variables. - Los KPI piezas en el sistema y producción por tick miden el rendimiento de la línea.
Qué cola produce qué efecto
| Línea | Efecto 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
| Cola | Capacidad | Productor | Consumidor |
|---|---|---|---|
cola1 | 2 | hAlimentador | hMaquina1 |
cola2 | 2 | hMaquina1 | hMaquina2 |
cola3 | 2 | hMaquina2 | hMaquina3 |
colaSalida | 3 | hMaquina3 | hSalida |
colaTel | 4 | M1, M2, M3 | hSupervisor |
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
- 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?
- 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.)
- Si
colaTelfuera de capacidad 1, ¿qué pasaría con M1, M2 y M3? Compara con la respuesta de la página Colas.