Programación Concurrente y Paralela. P(S) ; sección crítica P(S);



Documentos relacionados
Por ejemplo, el siguiente error conduce inmediatamente a un deadlock:

Concurrencia. Primitivas IPC con bloqueo

CDI Exclusión mutua a nivel alto. conceptos

MONITORES EN JAVA. Antonio Tomeu Control de la Concurrencia en Java: API Estándar

Concurrencia: Exclusión mutua y Sincronización

Concurrencia: deberes. Concurrencia: Exclusión Mutua y Sincronización. Concurrencia. Dificultades con la Concurrencia

1 HILOS (THREADS) EN JAVA

Java nos ofrece la clase Thread y la interfaz Runable que permiten que varios procesos estén funcionando de forma concurrente.

Benemérita Universidad Autónoma del Estado de Puebla

Receta general para resolver problemas de sincronización con semáforos

Object 1. Threads en Java

Concurrencia entre Procesos.

Mensajes. Interbloqueo

PROGRAMACIÓN EN JAVA

Threads. La plataforma JAVA soporta programas multhreading a través del lenguaje, de librerías y del sistema de ejecución. Dos.

SIMM: TEORÍA DE LOS S.O. I.E.S. JUAN DE LA CIERVA CURSO 2007/2008

Java y JVM: programación concurrente

Programación Orientada a Eventos

Tema 3. Monitores Programación Concurrente

4. Programación Paralela

Implementación de monitores POSIX

un programa concurrente

SISTEMAS OPERATIVOS AVANZADOS

Modulo 1 El lenguaje Java

Benemérita Universidad Autónoma del Estado de Puebla

8. Sentencia return y métodos

Java: Programación Multithread

TEMA 5: Control de la Concurrencia en Java (API Estándar)

Hilos en Java. Crear un Hilo. Detener un hilo. Fuente:

Concurrencia. Bibliografía: Introducción a los Sistemas de Bases de Datos Date, C.J.

2. Estructura de un programa en Java

PROGRAMACIÓN CONCURRENTE. Tema 5 Monitores

Transacciones y bloqueos en SQL-Server

Programación Concurrente en Java

CAPÍTULO 8. Comunicación y sincronización basada en variables compartidas

dit UPM Tema 3: Concurrencia /ejercicios Análisis y diseño de software José A. Mañas

Monitores. Implementación de un Buffer con monitores

Monitores Ing. Iván Medrano Valencia

Concurrencia en Java

Programación Avanzada para Sistemas de Telecomunicación. Objetos y clases. J.C. Cruellas. Objetos y clases

Secretos de la Programación Concurrente

Sistemas Operativos. Características de la Multiprogramación. Interacción entre Procesos. Características de la Multiprogramación

PROGRAMACION CONCURRENTE

Clases y Objetos. Informática II Ingeniería Electrónica

Programación Concurrente Recopilación de teoría referente a la materia

Capítulo IV. INTERBLOQUEO E INANICIÓN

Sistemas Operativos. Curso 2016 Procesos

1 (2 5 puntos) Responda con brevedad y precisión a las siguientes preguntas:

Q-flow Patrones básicos de Workflow

Hilos, comunicación y competencia entre procesos. Dr. Alonso Ramírez Manzanares 2-Sep-2010

COPIAS DE SEGURIDAD AUTOMÁTICAS DE DIRECCIONES CALLEÇPAÑA

Para leer la entrada de consola, lo primero que se hace es construir un Scanner que este asociado al flujo de entrada estándar System.

En cualquier caso, tampoco es demasiado importante el significado de la "B", si es que lo tiene, lo interesante realmente es el algoritmo.

11. Algunas clases estándar de Java (II)

Tema 4. Gestión de entrada/salida

Sistemas Operativos Práctica 4

9. Objetos y clases Clases

Tema 2. El lenguaje de programación Java (Parte 1)

Árboles. Cursos Propedéuticos Dr. René Cumplido M. en C. Luis Rodríguez Flores

GENERACIÓN DE CÓDIGO

PROGRAMACIÓN ORIENTADA A OBJETOS (L40629) Sabino Miranda-Jiménez

Identificadores, palabras reservadas, tipos de datos, operadores aritméticos y el sistema estándar de salida en Java

DEFINICION. Ing. M.Sc. Fulbia Torres Asignatura: Estructuras de Datos Barquisimeto 2006

Introducción a la Firma Electrónica en MIDAS

Ingeniería Superior de Informática. Curso 3º. Sistemas Operativos. Examen Final. TEORÍA. 31 de Enero de 2005

EXCEPCIONES EN JAVA. Las sentencias que tratan las excepciones son try y catch. La sintaxis es:

Práctico de Procesos, Hilos y Deadlock

Uso de excepciones en Java

Programación Orientada a Objetos con Java

Capitulo VI. Conclusiones.

Procesos. Planificación del Procesador.

Solución Examen Febrero 2006

SOLUCION EXAMEN junio 2006

Elementos requeridos para crearlos (ejemplo: el compilador)

Cómo elaborar una Nómina?

Sistemas Operativos Práctica 3

Programación Concurrente en Java

Introducción a la programación orientada a objetos

Ejercicio 1 (3 puntos).-

Capítulo 9. Archivos de sintaxis

RESUMEN DE CONCEPTOS BASICOS DE PROGRAMACION JAVA

Definición de clases: Herencia, polimorfismo, ligadura dinámica

Contenido. Sistema de archivos. Operaciones sobre archivos. Métodos de acceso a archivos. Directorio. Sistema de archivos por capas.

Capítulo 1 Introducción a la Computación

Guía sobre los cambios del nuevo sitio Web de Central Directo

NIFBdM B-12 COMPENSACIÓN DE ACTIVOS FINANCIEROS Y PASIVOS FINANCIEROS

Gestión de Permisos. Bizagi Suite. Copyright 2014 Bizagi

Mensajes. (versión preliminar)

INTRODUCCION A LA PROGRAMACION DE PLC

PHP y MySQL. Indice: Switch Bucles For While do...while

PROBLEMAS CON SU CLAVE? Cliente Nuevo Puedo solicitar acceso a la Banca en Línea (Contrato Uso de Canales de Autoatención) a través del Portal?

Departamento CERES Área de Tarjetas Inteligentes Manual de Usuario

Objetivo: Introducción conceptual y aplicación básica de los lenguajes del lado del servidor.

Examen escrito de Programación 1

3. GESTIÓN DE CONFIGURACIÓN DE SOFTWARE

Estructuras de Datos y Algoritmos Tecnólogo en Informática

Manual de Usuario Comprador. Módulo Administración de Presupuesto. Iconstruy e S.A. Serv icio de Atención Telefónica:

Una base de datos es una colección de información ordenada e interrelacionada que es de importancia para una empresa.

Sistemas Operativos II Febrero 2009 Nombre:

Sistemas de archivos distribuidos. Alvaro Ospina Sanjuan

Transcripción:

2.5.2 Monitores Los semáforos, a pesar de su sencillez de uso, son el equivalente a las instrucciones goto y el manejo de apuntadores en los lenguajes de programación imperativos: son muy susceptibles a errores. Su utilización exige disciplina. Por ejemplo, el siguiente error conduce inmediatamente a un deadlock: P(S) ; sección crítica P(S); Generalmente resulta difícil distinguir entre los dos usos de los semáforos (i.e. para exclusión mutua y condición de sincronización) en un programa sin una revisión detallada de todo el código. Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores de programación, proporcionando construcciones de programación de mayor nivel de abstracción que los semáforos, ya que los monitores están en estrecha relación con la programación orientada a objetos, además de ser la primitiva para sincronización interconstruída que ofrece Java. Un monitor es un módulo opaco que encapsula servicios mediante métodos de acceso, así como sus variables locales y globales. La única forma para manipular o acceder las variables dentro del monitor es invocando alguno de los métodos de servicio. Solamente se permite que un hilo esté activo a la vez dentro del monitor ejecutando uno de los métodos de servicio, asegurando exclusión mutua y previniendo implícitamente la presencia de condiciones de contención. Cada objeto monitor tiene un candado, el compilador del lenguaje de programación genera el código al comienzo de cada método de servicio para adquirir el candado y al final para liberarlo. Si el monitor está ocupado por algún hilo (i.e. se apropió del candado), los hilos siguientes que invoquen alguno de los métodos de servicio del monitor (i.e. intenten entrar al monitor) serán bloqueados e incorporados en la lista de espera para adquirir el candado. Al igual que los semáforos, los monitores ofrecen las dos formas de sincronización: la exclusión mutua está garantizada por el compilador implícitamente al invocar métodos de servicio. Para proporcionar mecanismos para sincronización de eventos (condición de sincronización) un monitor puede contener variables de condición, las cuales pueden manipularse mediante las operaciones signal y wait (que son análogas a las operaciones P y V en semáforos binarios, respectivamente). Su funcionamiento se describe enseguida: wait: Un hilo que espera a que ocurra un evento indicado por una variable de condición deja al monitor temporalmente, libera el candado y se une a la lista de hilos bloqueados correspondiente a esa variable de condición. signal: Cada señal con respecto a una variable de condición despierta a un hilo de la lista de hilos bloqueados correspondiente a esa variable de condición (no necesariamente el que lleva más tiempo en espera), si no hay ningún hilo esperando, la señal no se almacena y no tiene efecto (contrastando a la manera en la cual los semáforos funcionan). Dado que las operaciones de liberar al candado 1

y unirse a la lista de espera por una variable de condición son operaciones atómicas no hay riesgo de pérdida de las señales (i.e. `wakeup'). Al hilo despertado por la señal se le desplaza de esa lista de bloqueados y se le coloca en la lista de hilos en espera por entrar al monitor. Una vez que el candado sea readquirido, el hilo en cuestión continúa la ejecución del método de servicio que invocó anteriormente (i.e. la primera vez para entrar al monitor). Métodos de Servicio: metodo1(..) metodo2(..) Hilos esperando entrar al monitor : (invocaron a un método de servicio) metodon(..) Datos Globales Variables de Condición: Cond 1 lista de bloqueados por Cond 1 Cond 2 lista de bloqueados por Cond 2 : : Condm lista de bloqueados por Condm Figura 2.2: Estructura de los Monitores. Las variables de condición de los monitores no tienen valor, se le puede considerar como el nombre de la lista de hilos bloqueados (nombre de un evento). Note que las variables de condición y los semáforos difieren en dos maneras: una señal realizada en una variable cuya lista de hilos bloqueados está vacía no tiene efecto mientras que la invocación a V incrementa el contador del semáforo; a su vez, una invocación a la primitiva wait en una variable de condición siempre bloquea al hilo hasta que reciba una señal mientras que una invocación a P decrementa el contador del semáforo si su valor es positivo y no bloquea al hilo. El manejo de las variables de condición de los monitores se implanta de acuerdo a una de las diferentes disciplinas de señalización: 1. signal and exit: si un hilo que esté ejecutándose dentro del monitor emite una señal respecto una variable de condición entonces debe dejar el monitor inmediatamente ejecutando una instrucción return en el método de servicio que invocó. Se despierta a un hilo de la lista de hilos bloqueados correspondiente a la variable de condición y continúa ejecutándose dentro del monitor. 2. signal and wait: el hilo que recibe la señal (señalado o despertado) se ejecuta dentro del monitor, mientras que el hilo que emitió la señal (señalador) espera a que el señalado salga del monitor y entonces pueda continuar el señalador. 3. signal and continue: el hilo despertado espera a que el señalador deje el monitor y entonces continúa su ejecución dentro del monitor. En la Figura 2.3 se ilustra el funcionamiento de tales disciplinas (suponemos que el tiempo hacia abajo). Los monitores en Java utilizan la disciplina signal and continue, pero revisaremos primero a la más sencilla que es signal and exit. Los métodos de servicio se indican con la palabra reservada synchronized indicando que un sólo hilo se le permite 2

ejecutar el método a la vez, el método wait(condvar) permite indicar la espera de una variable de condición, por su parte notify(condvar) indica la emisión de una señal. Figura 2.3: Disciplinas de señalamiento en los Monitores. Para la disciplina signal and exit, se asume lo siguiente: 1. Después de emitir una señal respecto una variable de condición, el señalador debe salir inmediatamente del monitor, de tal forma que ninguna variable cambia antes de que el hilo despertado continúe ejecutándose dentro del monitor. Por tanto, el hilo despertado encuentra que la condición de la señal es verdadera. 2. Al hilo despertado se le otorga prioridad para proceder inmediatamente al monitor sobre aquellos hilos que estaban esperando entrar al monitor mediante la invocación de un método de servicio. Como ejemplo, mostramos (en pseudo código) un fragmento para la solución al problema del productor-consumidor utilizando un buffer limitado (archivo Monitor/bbse.java): public synchronized void deposit(double data) { if (count == size) wait(notfull); buf[rear] = data; 3

rear = (rear+1) % size; count++; if (count == 1) notify(notempty); Programación Concurrente y Paralela public synchronized double fetch() { double result; if (count == 0) wait(notempty); result = buf[front]; front = (front+1) % size; count--; if (count == size-1) notify(notfull); return result; Si el buffer está lleno, el productor se bloquea con la invocación al método wait respecto a la variable de condición notfull, el productor es despertado por el consumidor mediante la señal notify cuando deja un espacio libre en el buffer. Si el buffer está vacío, el consumidor se bloquea respecto la variable notempty y a su vez será despertado por el productor cuando éste coloque un elemento en el buffer. Para la disciplina signal and continue, no se requiere que el hilo que emitió la señal salga del monitor, ni tampoco que el hilo despertado tenga prioridad para proceder dentro del monitor sobre los demás hilos que están esperando entrar (compiten por el candado). Por ello, no se puede garantizar que la condición que condujo la emisión de la señal continue siendo válida cuando el hilo que fue despertado entre de nuevo al monitor, ya que antes de dejar al monitor el hilo que emitió la señal podrá haber cambiado datos y/o alterado el estado interno del monitor. A su vez, los hilos que compiten por entrar al monitor pueden adelantárseles a los hilos que están esperando a que ocurra el evento de la variable de condición, lo cual resulta en una forma de inanición (pues el tiempo de espera asociado a la variable de condición no está limitado). Debido a ello, se deben tomar precauciones para que el hilo que estaba esperando por la variable de condición verifique que ésta haya ocurrido una vez que entra de nuevo al monitor, i.e. fundamentalmente se debe cambiar if (condicion) wait(); // bloqueo en signal-and-exit por un bucle: while (condicion) wait(); // bloqueo en signal-and-continue incluso permitiendo que la señal pueda despertar a más de un hilo bloqueado (i.e una forma de broadcast). Para construir un monitor en Java, se debe utilizar el modificador synchronized en cada método de servicio (i.e que requiera exclusión mutua), tales métodos generalmente son públicos pero pueden también ser privados. Cada objeto Java tiene un candado asociado; implícitamente, un hilo que quiera ejecutar un método synchronized de un objeto primero debe apropiarse del candado, bloqueándose si es que está en uso por otro hilo. Desafortunadamente, cada monitor en Java sólo tiene una variable de condición 4

anónima; todas las invocaciones a wait() y notify() (para bloquear y emitir una señal, respectivamente) se refieren automáticamente a esa variable anónima. Por su parte, la primitiva notifyall() permite despertar a todos los hilos que se encuentran bloqueados esperando por la variable de condición anónima. Como ejemplos, se muestran segmentos de código para los problemas productorconsumidor con buffer limitado (prog. Monitor/bbmo.java) y los filósofos comelones (Monitor/dpmo.java): public synchronized void deposit(double value) { while (count == numslots) try { wait(); catch (InterruptedException e) { System.err.println("interrupted out of wait"); buffer[putin] = value; putin = (putin + 1) % numslots; count++; // wake up the consumer if (count == 1) notify(); // since it might be waiting public synchronized double fetch() { double value; while (count == 0) try { wait(); catch (InterruptedException e) { System.err.println("interrupted out of wait"); value = buffer[takeout]; takeout = (takeout + 1) % numslots; count--; // wake up the producer if (count == numslots-1) notify(); // since it might be waiting return value; Nótese que no ocurren condiciones de contención sobre la variable compartida count. private void seeifstarving(int k) { if (state[k] == HUNGRY && state[left(k)]!= STARVING && state[right(k)]!= STARVING) { state[k] = STARVING; System.out.println("philosopher " + k + " is STARVING"); private void test(int k, boolean checkstarving) { 5

if (state[left(k)]!= EATING && state[left(k)]!= STARVING && (state[k] == HUNGRY state[k] == STARVING) && state[right(k)]!= STARVING && state[right(k)]!= EATING) state[k] = EATING; else if (checkstarving) seeifstarving(k); // simplistic naive check for starvation Programación Concurrente y Paralela public synchronized void takeforks(int i) { state[i] = HUNGRY; test(i, false); while (state[i]!= EATING) try {wait(); catch (InterruptedException e) { public synchronized void putforks(int i) { state[i] = THINKING; test(left(i), checkstarving); test(right(i), checkstarving); notifyall(); En este programa se utiliza un esquema simple para prevención de inanición. Dado que Java solamente soporta una variable de condición única en sus monitores no se puede utilizar un arreglo de variables de condición (una para cada filósofo) para bloquear a un filosofo hambriento que no puede comer. En lugar de ello, se utiliza notifyall() para despertar a todos los filósofos que estén esperando a que su vecino deje de comer; lo cual es muy ineficiente pues a lo más dos filósofos necesitan ser despertados. Consecuentemente, la mayoría de los métodos de monitores en Java siguen el siguiente patrón de diseño: public synchronized tipo metodo(...) {... notifyall(); // si alguna condición de espera fué alterada while(!condicion) try { wait(); catch (InterruptedException e) {... notifyall(); // si alguna condición de espera fué alterada A pesar de que los monitores en Java solamente tienen una variable de condición anónima, se puede utilizar un objeto para implantar una variable de condición con nombre, que actuará como un objeto para notificación: objeto compartido: Object obj = new Object(); 6

en un hilo: en el otro: synchronized(obj) { synchronized(obj) { if (!cond) if (cond) obj.notify(); try { obj.wait();... catch(interruptedexception e){... Dentro de un bloque de exclusión mutua en obj un hilo verifica la condición para ver si puede continuar, de lo contrario espera. El otro hilo cambia la condición y notifica al hilo en espera. Cuando se usa dentro de un monitor, un objeto de notificación juega el rol de una variable de condición con nombre. Cabe mencionar que las invocaciones anidadas a métodos de servicio de los monitores están sujetos a deadlocks: class S { class T { synchronized void f(t t) { synchronized void g(s s) {... t.g(...);...... s.f(...);... Aquí, s y t son referencias a monitores creados en las clases S y T respectivamente, y que son compartidos por dos hilos A y B en la siguiente secuencia de eventos: A: invoca s.f(t); B: invoca t.g(s); A: se bloquea al invocar t.g B: se bloquea al invocar s.f Para evitar deadlocks, se sugiere ordenar globalmente todos los objetos monitor y solicitar que todos los hilos que compiten por el candado del monitor sigan el mismo orden. 7