Soluciones concurrentes al problema de los filósofos comensales: monitores, semáforos y paso de mensajes
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, requiereTenedor → requiereTenedor 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.