Diferencia entre revisiones de «Monitores»
(→Definición: corregidos errores ortográficos) |
|||
(No se muestran 39 ediciones intermedias de 14 usuarios) | |||
Línea 1: | Línea 1: | ||
− | Idea desarrollada en los años 70 Brinch-Hansen y Hoare | + | Idea desarrollada en los años 70 Brinch-Hansen y Hoare (https://web.archive.org/web/20091229162223/http://java.sun.com/developer/Books/performance2/chap4.pdf), que notaron los siguientes problemas con respecto al uso de los semáforos: |
* Los semáforos son difíciles de usar. Es frecuente que el programador cometa errores al emplearlos. | * Los semáforos son difíciles de usar. Es frecuente que el programador cometa errores al emplearlos. | ||
* El compilador no asiste al programador en el desarrollo de programas concurrentes mediante semáforos, pues no ofrece ningún tipo de validación en tiempo de compilación. | * El compilador no asiste al programador en el desarrollo de programas concurrentes mediante semáforos, pues no ofrece ningún tipo de validación en tiempo de compilación. | ||
− | * No hay nada que obligue a usarlos. Puede suceder que el programador los necesite y lo desconozca | + | * No hay nada que obligue a usarlos. Puede suceder que el programador los necesite y lo desconozca. |
− | * Son independientes del recurso compartido | + | * Son independientes del recurso compartido. |
Los monitores tienen que estar integrados en el lenguaje de programación. | Los monitores tienen que estar integrados en el lenguaje de programación. | ||
Línea 13: | Línea 13: | ||
* Los datos son privados. | * Los datos son privados. | ||
* Ofrecen una serie de métodos públicos para acceder a dichos datos. | * Ofrecen una serie de métodos públicos para acceder a dichos datos. | ||
− | * En cada momento sólo puede haber un proceso activo en algún método del monitor, es decir, ejecutando código de esos métodos públicos del monitor. | + | * En cada momento sólo puede haber un proceso activo en algún método del monitor, es decir, ejecutando código de esos métodos públicos del monitor. Sería equivalente a decir que el recurso que queremos compartir se declara como monitor. Los procesos que usan el monitor son independientes unos de otros y cuando deseen usar el recurso, llamarán a los métodos del monitor que implementen la operación que se desea ejecutar. |
Permiten organizar procesos en espera mediante: | Permiten organizar procesos en espera mediante: | ||
Línea 19: | Línea 19: | ||
* Variables de condición: lista de procesos inicialmente vacía. | * Variables de condición: lista de procesos inicialmente vacía. | ||
* Primitivas: ''wait(c)'', añade el proceso p invocante a c y proceso p bloquea; ''signal(c)'', selecciona a uno de los procesos en c y lo pone en preparado. | * Primitivas: ''wait(c)'', añade el proceso p invocante a c y proceso p bloquea; ''signal(c)'', selecciona a uno de los procesos en c y lo pone en preparado. | ||
+ | |||
<source lang="java"> | <source lang="java"> | ||
Línea 24: | Línea 25: | ||
class recursoCompartido { | class recursoCompartido { | ||
− | |||
− | |||
private int recursoCompartido; | private int recursoCompartido; | ||
private Semaforo s = 1; | private Semaforo s = 1; | ||
public int get(void){ | public int get(void){ | ||
− | int ret; | + | int ret; #1 |
− | down(s); | + | down(s); #2 |
− | ret = recursoCompartido; | + | ret = recursoCompartido; #3 |
− | up(s); | + | up(s); #4 |
− | return ret; | + | return ret; #5 |
} | } | ||
public void set(int valor){ | public void set(int valor){ | ||
− | down(s); | + | down(s); #1 |
− | recursoCompartido = valor; | + | recursoCompartido = valor; #2 |
− | up(s); | + | up(s); #3 |
} | } | ||
} | } | ||
+ | </source> | ||
+ | |||
+ | Como vemos, los monitores se implementan con semáforos, son una abstracción de los mismos. | ||
+ | |||
+ | == Ejemplo del funcionamiento de una clase monitor == | ||
+ | |||
+ | Dado un cierto recurso compartido protegido por una clase monitor denominada ''RecursoCompartido'' con los siguientes métodos: | ||
+ | |||
+ | * '''get''', permite obtener el valor del recurso compartido, devuelve un entero. | ||
+ | * '''set''', permite establecer el valor del recurso compartido. | ||
+ | |||
+ | Suponga ya creada un objeto RecursoCompartido para dos hilos h1 y h2: | ||
+ | <source lang="java"> | ||
+ | RecursoCompartido r = new RecursoCompartido(); | ||
</source> | </source> | ||
− | + | Dichos hilos tienen el siguiente código: | |
+ | |||
+ | * Lector (h1): | ||
+ | |||
+ | <source lang="java"> | ||
+ | int valor; | ||
+ | for(int j=0; j<2; j++) { #1 | ||
+ | valor=r.get(); #2 | ||
+ | print(valor); #3 | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | * Escritor (h2): | ||
+ | |||
+ | <source lang="java"> | ||
+ | int i=0; | ||
+ | for(int j=0; j<2; j++) { #1 | ||
+ | r.set(i); #2 | ||
+ | i++; #3 | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Suponiendo turno rotatorio estricto con quantum de 4 unidades de tiempo y que el planificador da paso en primer lugar al hilo h1. El cronograma con la representación de la ejecución sería el siguiente: | ||
+ | |||
+ | < = lanzamiento del proceso | ||
+ | > = finalización del proceso | ||
+ | x = indica que el proceso está asignado al procesador en ese momento. | ||
+ | B = el proceso pasa a estado bloqueado | ||
+ | P = el proceso pasa a estado preparado | ||
+ | |||
+ | Asignación del recurso procesador | ||
+ | |||
+ | | 1 |2.1|2.2|2.3| | |2.4|2.5| 3 | 1 | | | | |2.1|2.2|2.3|2.4| | | | |2.5| 3 | 1 | | | ||
+ | h1 <---|---|---|---P | |---|---|---|---P | | | |---|---|---|---| | | | |---|---|---> | | ||
+ | | | | | | 1 |2.1| | | | |2.2|2.3| 3 | 1 | | | | |2.1|2.2|2.3| 3 | | | | 1 | | ||
+ | h2 | | | | <---|---B P | | |---|---|---|---P | | | |---|---|---|---| | | |---> | ||
+ | ----|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| | ||
+ | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ||
+ | |||
+ | Nota: Los números de la parte superior a los guiones, indican el número de instrucción que | ||
+ | se está ejecutando en dicho momento. En el caso de los 2.1, 2.2 y sucesivos se | ||
+ | refieren al número de instrucción qué internamente se ejecutan en el get() y set() | ||
+ | del monitor (Ver la implementación de la clase monitor de RecursoCompartido vista en clase). | ||
+ | |||
+ | [[Usuario:Migoligon|Migoligon]] 16:51 4 dic 2011 (UTC)Porqué h1 no tiene la P de preparado en el 2.4 ni h2 en el último 3, y porqué h2 no se bloquea en el 2º down?? | ||
+ | |||
+ | H1 y H2 si pasan a preparado en 2.4 y 3 respectivamente, si no está la P será por olvido. Por otro lado, H2 no bloquea en el segundo down porque el semáforo en ese instante es s=1. El h1 en el instante 2.4 lo pone a 1, y pasa a preparado por consumir todo el quantum. Cuando h2 hace el down, el contador sigue a 1, lo decrementa y sigue ejecutando código. | ||
+ | |||
+ | En la página de [https://1984.lsi.us.es/wiki-ssoo/index.php/Discusi%C3%B3n:Monitores discusión] hay un ejemplo en java. | ||
+ | |||
+ | Creo que una solución mas correcta es la siguiente: | ||
+ | Asignación del recurso procesador | ||
+ | |||
+ | | 1 | 2 |2.1|2.2| | | |2.3|2.4|2.5| 3 | | | | | 1 | 2 |2.1|2.2| | |2.3|2.4|2.5| 3 | | ||
+ | h1 <---|---|---|---P | | |---|---|---|---P | | | |---|---|---|---P | |---|---|---|---P | ||
+ | | | | | | 1 | 2 |2.1| | | | |2.2|2.3| 3 | 1 | | | | | 2 |2.1| | | | | | ||
+ | h2 | | | | <---|---|---B | P | |---|---|---|---P | | | |---|---B | P | | | ||
+ | ----|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| | ||
+ | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ||
+ | |||
+ | |||
+ | | | | | | 1 | | ||
+ | h1 | | | | |---> | ||
+ | |2.2|2.3| 3 | 1 | | | ||
+ | h2 |---|---|---|---> | | ||
+ | |---|---|---|---|---| | ||
+ | 25 26 27 28 29 30 | ||
+ | |||
+ | --[[Usuario:Mangonvil1|Mangonvil1]] 17:20 14 dic 2011 (UTC)Creo que esta solución sería más correcta puesto que la línea 2 del código de cada hilo(en el hilo 1 el get() y en el hilo 2 el set(i)) hay que tratarla como una unidad de ejecución más. (Pendiente de que Pablo le de el visto bueno) | ||
+ | |||
+ | Esta solución es incorrecta (creo que lo comentó también Pablo en clase) ya que las llamadas a las funciones son en realidad un puntero apuntando a una dirección de la memoria en la que se encuentra esa función (apuntará a la primera línea de ejecución de la función). Para verlo con un ejemplo más de "andar por casa", digamos que sería el equivalente a sustituir en el código del hilo1 la linea #2 por todas las líneas de la función en si, #2.1 #2.2 #2.3 #2.4 y #2.5, la llamada a la función no cuenta como una ejecución más.--[[Usuario:Josazcrom|Josazcrom]] 10:39 14 dic 2011 (UTC) | ||
== Fuentes == | == Fuentes == | ||
− | + | Tema 4 | |
+ | http://hpjpc.googlecode.com/files/HPJPC%20Christopher%20and%20Thiruvathukal.pdf | ||
+ | |||
+ | |||
+ | 5.7[[Mensajería | Mensajería]] |
Revisión actual del 17:31 2 abr 2020
Idea desarrollada en los años 70 Brinch-Hansen y Hoare (https://web.archive.org/web/20091229162223/http://java.sun.com/developer/Books/performance2/chap4.pdf), que notaron los siguientes problemas con respecto al uso de los semáforos:
- Los semáforos son difíciles de usar. Es frecuente que el programador cometa errores al emplearlos.
- El compilador no asiste al programador en el desarrollo de programas concurrentes mediante semáforos, pues no ofrece ningún tipo de validación en tiempo de compilación.
- No hay nada que obligue a usarlos. Puede suceder que el programador los necesite y lo desconozca.
- Son independientes del recurso compartido.
Los monitores tienen que estar integrados en el lenguaje de programación.
Definición
Un monitor es una estructura del lenguaje cuyas principales características son:
- Los datos son privados.
- Ofrecen una serie de métodos públicos para acceder a dichos datos.
- En cada momento sólo puede haber un proceso activo en algún método del monitor, es decir, ejecutando código de esos métodos públicos del monitor. Sería equivalente a decir que el recurso que queremos compartir se declara como monitor. Los procesos que usan el monitor son independientes unos de otros y cuando deseen usar el recurso, llamarán a los métodos del monitor que implementen la operación que se desea ejecutar.
Permiten organizar procesos en espera mediante:
- Variables de condición: lista de procesos inicialmente vacía.
- Primitivas: wait(c), añade el proceso p invocante a c y proceso p bloquea; signal(c), selecciona a uno de los procesos en c y lo pone en preparado.
class recursoCompartido {
private int recursoCompartido;
private Semaforo s = 1;
public int get(void){
int ret; #1
down(s); #2
ret = recursoCompartido; #3
up(s); #4
return ret; #5
}
public void set(int valor){
down(s); #1
recursoCompartido = valor; #2
up(s); #3
}
}
Como vemos, los monitores se implementan con semáforos, son una abstracción de los mismos.
Ejemplo del funcionamiento de una clase monitor
Dado un cierto recurso compartido protegido por una clase monitor denominada RecursoCompartido con los siguientes métodos:
- get, permite obtener el valor del recurso compartido, devuelve un entero.
- set, permite establecer el valor del recurso compartido.
Suponga ya creada un objeto RecursoCompartido para dos hilos h1 y h2:
RecursoCompartido r = new RecursoCompartido();
Dichos hilos tienen el siguiente código:
- Lector (h1):
int valor;
for(int j=0; j<2; j++) { #1
valor=r.get(); #2
print(valor); #3
}
- Escritor (h2):
int i=0;
for(int j=0; j<2; j++) { #1
r.set(i); #2
i++; #3
}
Suponiendo turno rotatorio estricto con quantum de 4 unidades de tiempo y que el planificador da paso en primer lugar al hilo h1. El cronograma con la representación de la ejecución sería el siguiente:
< = lanzamiento del proceso > = finalización del proceso x = indica que el proceso está asignado al procesador en ese momento. B = el proceso pasa a estado bloqueado P = el proceso pasa a estado preparado Asignación del recurso procesador | 1 |2.1|2.2|2.3| | |2.4|2.5| 3 | 1 | | | | |2.1|2.2|2.3|2.4| | | | |2.5| 3 | 1 | | h1 <---|---|---|---P | |---|---|---|---P | | | |---|---|---|---| | | | |---|---|---> | | | | | | 1 |2.1| | | | |2.2|2.3| 3 | 1 | | | | |2.1|2.2|2.3| 3 | | | | 1 | h2 | | | | <---|---B P | | |---|---|---|---P | | | |---|---|---|---| | | |---> ----|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Nota: Los números de la parte superior a los guiones, indican el número de instrucción que se está ejecutando en dicho momento. En el caso de los 2.1, 2.2 y sucesivos se refieren al número de instrucción qué internamente se ejecutan en el get() y set() del monitor (Ver la implementación de la clase monitor de RecursoCompartido vista en clase).
Migoligon 16:51 4 dic 2011 (UTC)Porqué h1 no tiene la P de preparado en el 2.4 ni h2 en el último 3, y porqué h2 no se bloquea en el 2º down??
H1 y H2 si pasan a preparado en 2.4 y 3 respectivamente, si no está la P será por olvido. Por otro lado, H2 no bloquea en el segundo down porque el semáforo en ese instante es s=1. El h1 en el instante 2.4 lo pone a 1, y pasa a preparado por consumir todo el quantum. Cuando h2 hace el down, el contador sigue a 1, lo decrementa y sigue ejecutando código.
En la página de discusión hay un ejemplo en java.
Creo que una solución mas correcta es la siguiente:
Asignación del recurso procesador | 1 | 2 |2.1|2.2| | | |2.3|2.4|2.5| 3 | | | | | 1 | 2 |2.1|2.2| | |2.3|2.4|2.5| 3 | h1 <---|---|---|---P | | |---|---|---|---P | | | |---|---|---|---P | |---|---|---|---P | | | | | 1 | 2 |2.1| | | | |2.2|2.3| 3 | 1 | | | | | 2 |2.1| | | | | h2 | | | | <---|---|---B | P | |---|---|---|---P | | | |---|---B | P | | ----|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| | | | | 1 | h1 | | | | |---> |2.2|2.3| 3 | 1 | | h2 |---|---|---|---> | |---|---|---|---|---| 25 26 27 28 29 30
--Mangonvil1 17:20 14 dic 2011 (UTC)Creo que esta solución sería más correcta puesto que la línea 2 del código de cada hilo(en el hilo 1 el get() y en el hilo 2 el set(i)) hay que tratarla como una unidad de ejecución más. (Pendiente de que Pablo le de el visto bueno)
Esta solución es incorrecta (creo que lo comentó también Pablo en clase) ya que las llamadas a las funciones son en realidad un puntero apuntando a una dirección de la memoria en la que se encuentra esa función (apuntará a la primera línea de ejecución de la función). Para verlo con un ejemplo más de "andar por casa", digamos que sería el equivalente a sustituir en el código del hilo1 la linea #2 por todas las líneas de la función en si, #2.1 #2.2 #2.3 #2.4 y #2.5, la llamada a la función no cuenta como una ejecución más.--Josazcrom 10:39 14 dic 2011 (UTC)
Fuentes
Tema 4 http://hpjpc.googlecode.com/files/HPJPC%20Christopher%20and%20Thiruvathukal.pdf
5.7 Mensajería