Control de planta

Diseño paso a paso

Un método repetible para pasar del enunciado de una instalación a su programa concurrente. Lo desarrollamos con un ejemplo completo: una célula de etiquetado donde las piezas llegan por una cinta, se etiquetan de una en una y salen por otra cinta; la etiquetadora tiene un cargador de 50 etiquetas y un operario lo repone cuando se agota.

Paso 1 · Inventario de elementos

ElementoEntradas (sensores)Salidas (actuadores)
Cinta de entradabarrera de llegada de piezamarcha/paro
Etiquetadorapresencia de pieza en su interiorciclo de etiquetado, contador de etiquetas
Cinta de salidabarrera de salidamarcha/paro
Cargador de etiquetascontador restante— (lo repone el operario)

Paso 2 · Actividades concurrentes → hilos

Pregunta clave: ¿qué cosas ocurren a la vez? Cada una es un hilo:

Paso 3 · Recursos y capacidades

Paso 4 · Relaciones de sincronización

Cada junta productor/consumidor recibe su pareja sp/sc, y cada recurso compartido, su semáforo:

SemáforoValor inicialSignificado
spEntradaEti1hueco en la etiquetadora (productor: hEntrada)
scEntradaEti0pieza presente en la etiquetadora (consumidor: hEtiquetadora)
spEtiSalida1hueco en la cinta de salida
scEtiSalida0pieza etiquetada en la salida
sEtiquetas50etiquetas restantes en el cargador
sAviso0señal «cargador agotado» para el operario

Paso 5 · Bucle de cada hilo

semaforo spEntradaEti = 1, scEntradaEti = 0;
semaforo spEtiSalida  = 1, scEtiSalida  = 0;
semaforo sEtiquetas   = 50;
semaforo sAviso       = 0;

void hEntrada() {
    while (1) {
        cintaEntrada(1);                 // cinta en marcha
        while (!sensorLlegada());        // hasta que llegue una pieza
        cintaEntrada(0);
        wait(spEntradaEti);              // espera hueco en la etiquetadora
        transferirAEtiquetadora();       // empuja la pieza dentro
        signal(scEntradaEti);            // la etiquetadora ya tiene pieza
    }
}

void hEtiquetadora() {
    while (1) {
        wait(scEntradaEti);              // espera pieza
        wait(sEtiquetas);                // gasta una etiqueta (si hay 0, bloquea)
        etiquetar();                     // ciclo de etiquetado
        wait(spEtiSalida);               // espera hueco en la salida
        transferirASalida();
        signal(spEntradaEti);            // su posición queda libre
        signal(scEtiSalida);             // hay pieza etiquetada en la salida
    }
}

void hSalida() {
    while (1) {
        wait(scEtiSalida);               // espera pieza etiquetada
        cintaSalida(1);
        while (!sensorSalida());         // hasta que la pieza abandone
        cintaSalida(0);
        signal(spEtiSalida);             // el hueco vuelve a estar libre
    }
}

void hOperario() {
    while (1) {
        wait(sAviso);                    // duerme hasta que falten etiquetas
        reponerCargador();               // el operario carga 50 etiquetas
        for (int i = 0; i < 50; i++)
            signal(sEtiquetas);          // repone los 50 permisos
    }
}

int main() {
    concurrente {
        hEntrada();
        hEtiquetadora();
        hSalida();
        hOperario();
    }
}

Paso 6 · Completar el aviso del cargador

Falta que alguien haga signal(sAviso). Lo natural es en la propia etiquetadora cuando detecta el cargador casi vacío; con semáforo contador basta comprobar antes de esperar:

// dentro de hEtiquetadora, justo antes de wait(sEtiquetas):
if (etiquetasRestantes() == 1)
    signal(sAviso);              // avisa con antelación al operario

Paso 7 · Verificación de invariantes

Antes de darlo por bueno, repasa la lista:

Paso 8 · Traducción a C++ moderno

std::binary_semaphore spEntradaEti(1), scEntradaEti(0);
std::binary_semaphore spEtiSalida(1),  scEtiSalida(0);
std::counting_semaphore<50> sEtiquetas(50);
std::binary_semaphore sAviso(0);

// wait(s)  →  s.acquire();     signal(s)  →  s.release();
// Los hilos se lanzan como std::jthread para parada ordenada:

int main() {
    std::jthread t1(hEntrada), t2(hEtiquetadora),
                 t3(hSalida),  t4(hOperario);
}
💡 Regla nemotécnica

Por cada junta de la instalación escribe dos frases: «el productor espera hueco antes de depositar y avisa elemento después» y «el consumidor espera elemento antes de retirar y avisa hueco después». Con esas dos frases y el inventario de recursos, el programa sale solo.