Soluciones concurrentes al problema de los filósofos comensales: monitores, semáforos y paso de mensajes

Clasificado en Informática

Escrito el en español con un tamaño de 5,65 KB

Implementaciones corregidas del problema de los filósofos comensales

Introducción

El siguiente documento presenta tres implementaciones en pseudocódigo del problema de los filósofos comensales: una usando monitores, otra con semáforos y una tercera basada en comunicación por mensajes. He corregido errores ortográficos, gramaticales y de mayúsculas/minúsculas, ajustado los identificadores y la sintaxis de pseudocódigo para mayor claridad, sin eliminar ni omitir contenido original.

1. Implementación con monitor (pseudocódigo corregido)

Monitor que gestiona la obtención y liberación de tenedores evitando condiciones de carrera.

monitor comida_filosofo;

enum estado_t { PENSANDO, HAMBRIENTO, COMIENDO };
estado_t estado[5];
condition requiereTenedor[5];

void obtieneTenedores(int i) {
    estado[i] = HAMBRIENTO;
    // Si alguno de los vecinos está comiendo, esperar
    if ((estado[(i + 1) % 5] == COMIENDO) || (estado[(i + 4) % 5] == COMIENDO))
        wait(requiereTenedor[i]);
    estado[i] = COMIENDO;
}

void liberaTenedor(int i) {
    estado[i] = PENSANDO;
    // Despertar al vecino derecho si puede comer
    if ((estado[(i + 1) % 5] == HAMBRIENTO) && (estado[(i + 2) % 5] != COMIENDO))
        signal(requiereTenedor[(i + 1) % 5]);
    // Despertar al vecino izquierdo si puede comer
    if ((estado[(i + 4) % 5] == HAMBRIENTO) && (estado[(i + 3) % 5] != COMIENDO))
        signal(requiereTenedor[(i + 4) % 5]);
}

// Inicialización
for (int i = 0; i < 5; i++) {
    estado[i] = PENSANDO;
    // requiereTenedor[i] está declarado como condition; su inicialización depende
    // de la implementación del monitor (no es necesario inicializar aquí).
}

void filosofo(int k) {
    while (true) {
        piensa();
        comida_filosofo.obtieneTenedores(k);
        come();
        comida_filosofo.liberaTenedor(k);
    }
}

// main: lanzar 5 filósofos en paralelo
main {
    paralelo(filosofo[0], filosofo[1], filosofo[2], filosofo[3], filosofo[4]);
}

2. Implementación con semáforos

Versión clásica que evita deadlock alterando el orden de adquisición de tenedores según paridad.

semaforo tenedor[5] = {1, 1, 1, 1, 1};

void filosofoImpar(int i) {
    while (true) {
        piensa();
        wait(tenedor[i]);
        wait(tenedor[(i + 1) % 5]);
        come();
        signal(tenedor[(i + 1) % 5]);
        signal(tenedor[i]);
    }
}

void filosofoPar(int j) {
    while (true) {
        piensa();
        // Orden invertido para evitar interbloqueo
        wait(tenedor[(j + 1) % 5]);
        wait(tenedor[j]);
        come();
        signal(tenedor[j]);
        signal(tenedor[(j + 1) % 5]);
    }
}

// main: lanzar filósofos (par/ímpar según índice)
main {
    paralelo(filosofo[0], filosofo[1], filosofo[2], filosofo[3], filosofo[4]);
}

3. Implementación basada en paso de mensajes (buzones y controlador)

Versión con envío y recepción de mensajes entre filósofos y un proceso controlador central que concede tenedores.

void filosofo(int i) {
    mensaje fmsg;
    while (true) {
        piensa();
        fmsg = "comer";
        send(pido_tenedores[i], fmsg);
        receive(tenedor_concedido[i], fmsg);
        come();
        fmsg = "dormir";
        send(suelto_tenedores[i], fmsg);
    }
}

void controlador() {
    // true indica tenedor disponible (1)
    bool tenedores[5] = { true, true, true, true, true };
    int contador;
    mensaje cmsg;
    while (true) {
        select {
            // recibir peticiones y conceder si ambos tenedores están libres
            for (int cont = 0; cont < 5; cont++) replicate {
                when (tenedores[cont] == true && tenedores[(cont + 1) % 5] == true)
                    receive(pido_tenedores[cont], cmsg);
                    tenedores[cont] = false;
                    tenedores[(cont + 1) % 5] = false;
                    send(tenedor_concedido[cont], cmsg);
                or
                // recibir liberaciones y marcar tenedores como libres
                for (int cont = 0; cont < 5; cont++) replicate {
                    receive(suelto_tenedores[cont], cmsg);
                    tenedores[cont] = true;
                    tenedores[(cont + 1) % 5] = true;
                }
            }
        }
    }
}

// main: crear buzones y lanzar filósofos y controlador
main {
    create_buzon(pido_tenedores);
    create_buzon(tenedor_concedido);
    create_buzon(suelto_tenedores);
    paralelo(filosofo[0], filosofo[1], filosofo[2], filosofo[3], filosofo[4], controlador);
}

Notas y correcciones realizadas

  • Se corrigieron errores ortográficos (por ejemplo, «hambiento» → «hambriento», «obitiene» → «obtiene», «mensage» → «mensaje»).
  • Se unificaron y aclararon identificadores para mayor coherencia (por ejemplo, requiereTenedorrequiereTenedor o tenedor_concedido).
  • Se ajustó la notación de índices con módulo para evitar referencias fuera de rango: se usa (i + 1) % 5, (i + 4) % 5, etc.
  • Se mantuvo todo el contenido original y su estructura lógica, pero se presentó en pseudocódigo más legible y correcto sintácticamente.
Recomendaciones

Dependiendo del entorno (lenguaje y runtime) que utilice, adapte la nomenclatura de wait, signal, send y receive, así como la creación de buzones y la construcción paralelo(...). Estas versiones son pseudocódigo didáctico para ilustrar alternativas de sincronización.

Fin del documento

Entradas relacionadas: