Referencia

Ejercicios resueltos

Cinco instalaciones completas resueltas en el estilo clásico de los ejercicios de sistemas de tiempo real: un hilo por dispositivo, parejas sp*/sc* en cada junta y regiones críticas explícitas. Intenta resolver cada uno por tu cuenta antes de mirar la solución.

Ejercicio 1 · Buffer limitado de envasado

Enunciado. Una llenadora produce botellas que deposita en un buffer de 4 posiciones; una empaquetadora las retira. Ni llenar ni empaquetar pueden simultanearse sobre la misma posición, y la llenadora no puede depositar si el buffer está lleno.

Ver solución
semaforo sHuecos = 4;     // posiciones libres
semaforo sBotellas = 0;   // botellas llenas
semaforo sMutex = 1;      // protege la cola

void hLlenadora() {
    while (1) {
        Botella b = llenarBotella();
        wait(sHuecos);
        wait(sMutex);
        buffer.push(b);
        signal(sMutex);
        signal(sBotellas);
    }
}

void hEmpaquetadora() {
    while (1) {
        wait(sBotellas);
        wait(sMutex);
        Botella b = buffer.pop();
        signal(sMutex);
        signal(sHuecos);
        empaquetar(b);
    }
}

Nota. El orden wait(sHuecos) antes de wait(sMutex) es obligatorio: si se tomara el mutex primero y luego se esperara hueco, la empaquetadora no podría entrar a vaciar (deadlock). Se puede ejecutar en el laboratorio de envasado.

Ejercicio 2 · Célula FMS: prensa, CNC y robot

Enunciado. Las piezas llegan a una posición de entrada; deben estamparse en la prensa y mecanizarse en el CNC, en ese orden, y salir por la posición de salida. Cada posición admite una pieza y el robot mueve piezas entre posiciones (región crítica).

Ver solución
semaforo spEntradaPrensa = 1, scEntradaPrensa = 0;
semaforo spPrensaCNC = 1,     scPrensaCNC = 0;
semaforo spCNCSalida = 1,     scCNCSalida = 0;
semaforo sRobot = 1;          // región crítica

void hEntrada() {
    while (1) {
        while (!barrera_entrada());      // espera pieza
        wait(spEntradaPrensa);           // hueco en la prensa
        wait(sRobot);
        coge(100, 0);  deja(0, 100);     // entrada → prensa
        signal(sRobot);
        signal(scEntradaPrensa);         // avisa a la prensa
    }
}

void hPrensa() {
    while (1) {
        wait(scEntradaPrensa);
        estampa();
        wait(spPrensaCNC);               // hueco en el CNC
        wait(sRobot);
        coge(0, 100);  deja(-100, 0);    // prensa → CNC
        signal(sRobot);
        signal(spEntradaPrensa);         // libera la prensa
        signal(scPrensaCNC);             // avisa al CNC
    }
}

void hCNC() {
    while (1) {
        wait(scPrensaCNC);
        mecaniza();
        wait(spCNCSalida);               // hueco en la salida
        wait(sRobot);
        coge(-100, 0);  deja(0, -100);   // CNC → salida
        signal(sRobot);
        signal(spPrensaCNC);             // libera el CNC
        signal(scCNCSalida);             // avisa a la salida
    }
}

void hSalida() {
    while (1) {
        wait(scCNCSalida);
        while (barrera_salida());        // espera a que retiren la pieza
        signal(spCNCSalida);             // la salida queda libre
    }
}

Nota. La misma solución vale con un solo semáforo sp/sc si se integran entrada y salida en los hilos de prensa y CNC. En el laboratorio puedes verla ejecutándose línea a línea.

Ejercicio 3 · Cadena de tres máquinas con cintas

Enunciado. Tres máquinas M0, M1 y M2 mecanizan en cadena las piezas que llegan por la cinta C0. Entre máquinas hay cintas C1 y C2, y de la última sale la cinta C3. Ninguna cinta admite más de una pieza; al final de cada cinta hay una barrera que detecta la llegada. Si una máquina falla, la pieza se rechaza a su contenedor.

Ver solución (simplificada)
semaforo sCintaP[3] = {1, 1, 1};   // cintas productoras (0, 1, 2)
semaforo sMaquinaC[3] = {0, 0, 0}; // consumidoras de cinta (máquinas)
semaforo sMaquinaP[3] = {1, 1, 1}; // productoras de pieza (máquinas)
semaforo sCintaC[3] = {0, 0, 0};   // cintas consumidoras (1, 2, 3)

void hCinta0() {                   // de la entrada a M0
    while (1) {
        cinta(0, 0);
        wait(sCintaP[0]);          // espera cinta vacía
        while (!barrera(0));       // espera pieza depositada
        cinta(0, 1);               // en marcha
        while (!barrera(1));       // hasta la barrera de M0
        cinta(0, 0);
        signal(sMaquinaC[0]);      // avisa a M0
    }
}

void hMaquina(int m) {
    while (1) {
        wait(sMaquinaC[m]);        // espera pieza en su cinta
        entrada(m);                // recoge la pieza
        signal(sCintaP[m]);        // la cinta queda libre
        if (procesado(m)) {        // sin error
            wait(sMaquinaP[m]);    // espera cinta de salida libre
            salida(m);             // deja la pieza
            signal(sCintaC[m]);    // avisa a la siguiente cinta
        } else {
            rechazo(m);            // pieza al contenedor de defectuosos
        }
    }
}

void hCinta(int c) {               // cintas 1 y 2
    while (1) {
        cinta(c, 0);
        wait(sCintaP[c]);          // hueco en la cinta
        wait(sCintaC[c - 1]);      // pieza de la máquina anterior
        cinta(c, 1);
        while (!barrera(c + 1));
        cinta(c, 0);
        signal(sMaquinaC[c]);      // avisa a la siguiente máquina
        signal(sMaquinaP[c - 1]);  // libera a la máquina anterior
    }
}

Nota. Cada cinta combina dos parejas sp/sc: como consumidora de la máquina anterior y como productora de la siguiente. Esta es la estructura general de cualquier línea con transportes intermedios.

Ejercicio 4 · La cuba electrolítica con 8 robots

Enunciado. Ocho robots alrededor de una cuba tratan piezas. Ningún robot puede acercarse a la cuba si el robot de su izquierda o el de su derecha está en ella; alrededor caben como mucho 7. Cada robot tiene su mesa de carga y su contenedor de piezas tratadas.

Ver solución
semaforo sRobot[8] = {1,1,1,1,1,1,1,1};  // permiso de cada robot
semaforo sCuba = 7;                        // plazas junto a la cuba

void hRobot(int n) {
    int izquierdo = (n + 7) % 8;           // el robot a su izquierda
    while (1) {
        while (!piezaEnMesa(n));           // espera pieza en su mesa
        baja(n);  cierra(n);  sube(n);     // coge la pieza
        wait(sCuba);                       // plaza junto a la cuba
        wait(sRobot[n]);
        wait(sRobot[izquierdo]);           // ni yo ni mi izquierdo…
        // …tampoco mi derecho: él esperará a mi semáforo
        mueveteACuba(n);
        baja(n);  abre(n);  sube(n);       // deposita en la cuba
        mueveteAMesa(n);
        signal(sRobot[n]);
        signal(sRobot[izquierdo]);
        signal(sCuba);
        sleep(10000);                      // tratamiento electrolítico
        wait(sCuba);
        wait(sRobot[n]);
        wait(sRobot[izquierdo]);
        mueveteACuba(n);
        baja(n);  cierra(n);  sube(n);     // recoge su pieza
        mueveteAContenedor(n);
        signal(sRobot[n]);
        signal(sRobot[izquierdo]);
        signal(sCuba);
        baja(n);  abre(n);  sube(n);
        mueveteAMesa(n);
    }
}

Nota. La restricción «ni el de mi izquierda ni el de mi derecha» se codifica pidiendo el permiso propio y el del vecino izquierdo; el vecino derecho, por simetría, pide el mío. El semáforo contador sCuba limita a 7 los robots en la zona.

Ejercicio 5 · Máquina con sistema transfer

Enunciado. Una máquina tiene cinco posiciones de mecanizado en línea, la entrada en la posición 0 y la salida en la 6. Un único transfer neumático mueve piezas entre posiciones adyacentes (una a la vez). Debe poder haber varias posiciones mecanizando simultáneamente piezas distintas.

Ver solución
semaforo sc[5] = {0,0,0,0,0};    // aviso de pieza a la posición i
semaforo sp[5] = {1,1,1,1,1};    // hueco en la posición i (para la anterior)
semaforo sTransfer = 1;          // el transfer es región crítica

void hPosicion(int n) {          // un hilo por posición (0 a 5)
    while (1) {
        if (n == 0)
            while (!entrada());  // espera pieza en la entrada
        else
            wait(sc[n - 1]);     // espera pieza de la posición anterior
        if (n > 0) mecaniza(n);  // mecaniza (si no es la entrada)
        if (n < 5)
            wait(sp[n]);         // espera hueco en la siguiente
        else
            while (salida());    // espera que la salida se vacíe
        wait(sTransfer);         // reserva el transfer
        transfiere(n, n + 1);    // mueve la pieza
        signal(sTransfer);       // libera el transfer
        if (n < 5) signal(sc[n]);      // avisa a la siguiente posición
        if (n > 0) signal(sp[n - 1]);  // libera la anterior
    }
}

Nota. Es el mismo esqueleto del pipeline, con la peculiaridad de que todas las etapas comparten un único transfer: por eso sTransfer envuelve solo el movimiento, dejando que los mecanizados se solapen. El código de cada posición es idéntico salvo los extremos: la entrada produce el primer sc y la salida consume el último.

Cómo seguir practicando