martes, 5 de abril de 2022

Los filósofos comensales en Java

 Para poder entender cómo solucionar los problemas encontrados en el ejercicios de los filósofos comensales, se ha desarrollado un programa en java que permita emular aleatoriamente el comportamiento de los filósofos.

El programa está estructurado en clases cuya función es ejecutar instrucciones específicas a la problemática encontrada.

La clase principal llamada Filósofos se presenta de la siguiente forma.


Por otro lado, tenemos las clases mesa y la clase filósofos que nos permiten especificar el comportamiento que tendrán tanto los comensales como la posición que deben guardar los tenedores para poder ser utilizados.









Los filósofos comensales

 Enunciado





Cinco filósofos se pasan al rededor de una mesa y pasan su vida cenando y pensando. Cada filósofo tiene un plato de espagueti y un tenedor a la izquierda de su plato. Para comer el espagueti son necesarios dos tenedores y cada filósofo solo puede tomar el que se encuentra a su derecha y a su izquierda. Si cualquier filósofo coge un tenedor y el otro está ocupado se quedará esperando con el tenedor en su la mano hasta que pueda tomar el otro tenedor para luego empezar a comer.

Historia

Es un problema clásico de las ciencias de la computación propuesto por el científico Edsger Dijkstra para representar los inconvenientes que plantea la sincronización de procesos en un sistema operativo


Desarrollo

Si dos filósofos adyacentes intentan tomar el mismo palillo a la vez se produce una condición de carrera: ambos compiten por lo mismo pero uno se queda sin comer.

Si todos los filósofos cogen el palillo de su derecha al mismo tiempo, todos se quedarán esperando eternamente porque alguien debe liberar el palillo que les falta, cosa que nadie hará porque todos se encuentran en la misma situación (esperando que alguno deje su palillo). Llegado esto, los filósofos se morirán de hambre. A este bloqueo mutuo se le denomina interbloqueo o deadlock.

El objetivo consiste en encontrar un recurso que permita que los filósofos nunca se mueran de hambre. Porque:

– Dos filósofos contiguos no pueden comer a la vez (exclusión mutua).

– Si un filósofo está comiendo, los contiguos no pueden hacerlo hasta que aquél termine (sincronización).

– El filósofo que termina de comer debe ceder los palillos para su posterior utilización (interbloqueo).

Este sencillo planteamiento resulta muy útil para los que estudian informática porque ayuda a pensar en los sistemas que tienen recursos limitados (en el ejemplo anterior los palillos son limitados) y en los clientes (programas y usuarios): hay que darles servicio (comida) a todos en un tiempo razonable.

Se trata de que los recursos sean utilizados de la manera más eficiente por todos los procesos implicados. Hay algoritmos para solucionarlo pero todos los métodos pasan por asignar prioridades y/o tiempos máximos de uso de los recursos.

La finalidad es demostrar que se presentarán problemas ante la falta de una apropiada sincronización y evitar la peligrosa condición de carrera.


martes, 29 de marzo de 2022

CONCURRENCIA


Definición

La concurrencia se refiere a dos o más eventos cuyo orden es no determinista, en otras palabras,  que no se puede predecir el orden de ocurrencia de éstos.

En un sistema operativo o en un programa la concurrencia se presenta cuando se necesita interactuar con otros, parte del procesamiento puede depender de datos obtenidos en fuentes externas por lo que la cooperación con hilos o procesos externos es fundamental.

Muchos de los lenguajes de programación convierten cada instrucción en una serie de operaciones de máquina de tal forma que una instrucción aparentemente simple implica la realización de varias operaciones de bajo nivel.

En un sistema operativo multitarea cuando un proceso agota el tiempo de procesador establecido o detiene su ejecución por otra razón, los valores almacenados en los registros se preservan para poder restaurarlo cuando la ejecución continúe.

El problema con la concurrencia, es que puede hacer que un programa funcione correctamente la mayor parte del tiempo, pero de vez en cuando puede fallar, es por eso que se utiliza una serie de acciones para prevenir o corregir dichos fallos.

Antes de entrar de lleno a las acciones correctivas, es necesario identificar algunos conceptos que son útiles para entender el concepto de las concurrencias.

Operación atómica: Se refiere a una manipulación de datos que requiere la garantía de que se ejecutará como una sola unidad de ejecución pues de lo contrario fallará completamente sin mostrar resultados parciales.

Condición de carrera: Conocido también como race condition, es una categoría de errores de programación que involucra a dos procesos que fallan al comunicarse su estado mutuo arrojando resultados inconsistentes.

Región crítica:  Área de código que requiere ser protegida de accesos simultáneos donde se realiza la modificación de datos compartidos.

Recurso compartido: Es un recurso al que se puede tener acceso desde más de un proceso.

Una de las opciones utilizadas para los problemas de concurrencia es el algoritmo de Peterson, propuesto en el año de 1957 y consiste en la utilización de banderas para indicar qué proceso puede entrar, pero además usa un turno para desempatar en caso de que ambos procesos busquen entrar a la vez.

Se podría decir que es un algoritmo amable, ya que si un proceso detecta que el otro fue primero en actualizar el turno, entonces lo deja pasar.

Otra posible solución para las eventualidades de concurrencia son los mecanismos de sincronización.

Regiones de exclusión mutua: mutexes. La palabra mutex se refiere a las regiones de exclusión mutua. Es un mecanismo que asegura que cierta región del código será ejecutada como si fuera atómica. Un mutex no implica que el código no se va a interrumpir mientras se está dentro de ésta región, el mutex implica un mecanismo de seguridad que mantiene en espera a cualquier hilo o proceso que quiera entrar a la sección crítica protegida hasta que el proceso que la está ejecutando salga de ella. Una región protegida debe ser mínima, es decir, tan corta como sea posible para evitar que otros hilos queden bloqueados fuera del área crítica y debe ser completa, en otras palabras, analizar con detenimiento cuál es el área a proteger y no arriesgarse a proteger de menos.

Semáforos, es una variable de tipo entero que tiene definida la interfaz de inicialización, se puede iniciar el semáforo a cualquier valor entero; decrementar, cuando un hilo decrementa el semáforo, si el valor es negativo, el hilo se bloquea y no puede continuar hasta que otro hilo incremente el semáforo; incrementar, cuando un hilo incrementa el semáforo, si hay hilos esperando, uno de ellos es despertado, el nombre que recibe ésta instrucción es signal, up, reléase, post.

Multiplex, Permite la entrada de no más de n procesos a la región crítica.

Torniquete, Esta estructura garantiza que un grupo de hilos o procesos pasa por un punto determinado de uno en uno incluso en un ambiente multiprocesador.

Apagador, Cuando se tiene una situación de exclusión categórica, varios procesos de la misma categoría pueden entrar a la sección crítica, pero procesos de dos categorías distintas deben tenerlo prohibido.

Barrera, Es una generalización que permite la sincronización entre varios hilos y no requiere que la categoría de cada uno de ellos sea distinta.

Cola, Se emplea cuando se tienen dos clases de hilos que deben proceder en pares. Este proceso es referido muchas veces como baile de salón ya que hace falta que haya un líder y un seguidor.

Rendezvous, término que se utiliza para “dar una cita”. Se busca que dos hilos se esperen mutuamente en cierto punto para continuar en conjunto.

Para terminar de entender el concepto se recomienda ver el video Concurrencia

Los filósofos comensales en Java

 Para poder entender cómo solucionar los problemas encontrados en el ejercicios de los filósofos comensales, se ha desarrollado un programa ...