ICOM 5007- SISTEMAS OPERATIVOS

 

Instructor: Héctor M Lugo Cordero

e-mail: hector.lugo@ece.uprm.edu

 

Laboratorio 4 – Exclusión Mutua (MUTEX)

I Objetivos

  • Estudio de la exclusión mutua y sus beneficios
  • Uso de la palabra synchronized
  • Desarrollo de una aplicación monitor para cotejar threads

 

II Teoría

 

Ya con las pasadas dos prácticas hemos aprendido diferentes maneras de correr varios procesos a la vez, ya sean pesados o livianos. Hoy cubriremos un poco más acerca de los procesos livianos (threads). Notamos con la práctica que a pesar de invocar lo métodos sleep e yield, existian ocasiones en las cuales dos threads leían una misma variable a un mismo tiempo. Esto no nos causaba problemas puesto que los procesos pueden compartir recursos de lectura entre si sin afectar el comportamiento de la aplicación general.

Sin embargo esto no ocurre al dos threads querer modificar una variable compartida, es posible que un thread espere tener un valor en especifico para modificar y no lo encuentre o peor aun lo pudo modificar pero entonces antes de utilizarlo otro thread le cambio el valor.    

Tenemos entonces que evitar este panorama, una manera sería trabajar con los waits para forzar a que los threads se bloqueen, esto puede ser peligroso ya que podría ocurrir un bloqueo permanente (DEADLOCK). Otra manera seria declarar el método run como estatico (static). Esto sin embargo no nos resolvería tampoco por dos razones (1) no podemos cambiar el prototipo del método y que la interfaz Runnable sepa que ese es el mismo que espera ver y (2) esto sólo nos haría tener un mismo método para todas las instancias de los objetos de esta clase con método static. Aun así podrían ser invocados simultáneamente, entonces ¿qué hacemos? 

La respuesta a esta pregunta se encuentra utilizando la palabra synchronized. La misma sincroniza métodos que la contengan en su prototipo (los hace mutuamente exclusivos o MUTEX por sus siglas en inglés).

 

public synchronized void setValue(int v)

 

Ahora si podemos añadir wait para esperar a que se pueda corer el thread y al final notifyAll para avisarle a otros threads que ya pueden correr.

 

private boolean canAttack;

 

public synchronized void attack(Enemy target)

{

            while(!canAttack)

            {

                        try

                        {

                                    wait();

                        }

                        catch(InterruptedException e)

                        {

                                   

                        }

            }

            canAttack = false;

            //add code to attack

            canAttack = true;

            notifyAll();

}

III Práctica

 

Esta vez modificarán el código de la práctica pasada añadiéndole una clase con métodos estáticos llamada Battle. Esta clase será un monitor que estará a cargo de verificar el estado de todos los threads (Hero, Enemy y Healer) que formen parte de la batalla.

Además ahora la batalla por parte de los héroes será de manera interactiva. Usted le dirá cuando ataque. ¿Cómo?  Como desee (podría ser entrando la letra A/a como señal para que ataque un héroe y B/b para el otro; lo mismo para los curadores (H/h).

Esta vez los métodos run de las clases (1) no tienen que ser un ciclo infinito, de hecho no deberían serlo puesto que el ciclo estará dentro de la clase Battle. (2) Estos métodos estarán synchronized.

PS: Si desean entretenerse un rato pueden añadirle sonido utilizando

File midiFile = new File("20-Still_More_Fighting.mid");

URL url = midiFile.toURI().toURL();

AudioClip mainTheme = Applet.newAudioClip(url);

mainTheme.loop(); //para un play infinito

mainTheme.play(); //para una sola vez de play

public abstract class Battle {

            private static ArrayList<Hero> heroes = new ArrayList<Hero>();

            private static ArrayList<Enemy> enemies = new ArrayList<Enemy>();

            private static ArrayList<Healer> healers = new ArrayList<Healer>();

           

            public static void addHero(Hero h){ }

            public static void addHealer(Healer h){ }

            public static void addEnemy(Enemy e) { }

           

            public static void startBattle(){ }

            public static boolean battleResult(){ }

            public static boolean battleEnded(){ }

            public static void endBattle(){ }

}