05 Monitores Flashcards
Desarrolle Monitores.
Intro: por que necesitamos más herramientas.
Hasta ahora vimos herramientas de sincronismo de muy bajo nivel, o los semáforos, que ya son utilizados a más alto nivel, pero que tienen el problema de que son muy desestructurados, lo que significa que son muy peligrosos para programar sistemas grandes: es suficiente que un proceso se olvide de hacer un signal en algún lado para que todo el sistema empiece a fallar. Lo peor de todo es que este tipo de errores son extremadamente difíciles de localizar. Uno ve que el programa no funciona según lo esperado, pero no hay una forma clara de realizar el seguimiento para poder localizar fácilmente el programa como sucede en los programas secuenciales.
Definición: abstracción de kernel.
En este contexto es que presentamos a los monitores. Los monitores proveen una primitiva estructurada de programación concurrente que concentra la responsabilidad de la corrección en módulos. Los monitores son una generalización del kernel del SO, donde las secciones críticas están centralizadas en un programa privilegiado. Los programas solicitan servicios que son ejecutados por el kernel. El kernel se ejecuta en modo hardware , asegurándose de no ser interrumpido por otro programa.
Los monitores son versiones descentralizadas del kernel monolítico. En vez de tener un programa centraliza el manejo de solicitudes de servicios que involucren algún recurso compartido como puede ser un dispositivo o datos, se define un monitor individual para cada grupo de objetos relacionados que requiere sincronización. Si las operaciones para un mismo monitor intentan ser ejecutadas por más de un proceso, el monitor se asegura de que sean ejecutadas garantizando la exclusión mutua. Si se intentan ejecutar las operaciones de distintos monitores, sus instrucciones pueden ejecutarse en forma intercalada.
POO
Algo que hace muy natural su comprensión es su analogía con el paradigma de poo, donde cada objeto tiene atributos que pueden ser públicos o privados, donde los públicos pueden ser accedidos libremente, pero los privados pueden ser manipulados únicamente mediante métodos públicos. En el caso de los monitores, los atributos serían privados, y si bien pueden ser accedidos mediante métodos públicos, un monitor además asegura que no podrá haber más de un proceso ejecutando un método al mismo tiempo.
Ej trivial de monitor
Si tenemos un contador que queremos utilizar en varios procesos, una forma de lograr excl. mutua es encapsulando el contador en un monitor, y que solamente pueda ser accedido mediante el método increment del monitor. Como por definición solamente un proceso puede ejecutar acciones sobre el monitor, queda asegurada la exclusión mutua. Ahora bien, como se logra hacer que un solo proceso ejecute métodos del monitor al mismo tiempo?
Condvars
Según la bibliografía, hay dos formas de implementar monitores; tanto el libro como la materia se centran en la implementación que hace uso de las Condition variables. Las cond. var. son entidades que no guardan ningún valor pero que tienen asociada una cola y 3 métodos:wait, signal e isEmpty.
Finalmente, hay una convención para nombrar las cond. var. de forma que el nombre indique la condición que se debe cumplir para que uno pueda acceder al monitor.
Para visualizar esto de una mejor manera, veamos el ejemplo de un monitor que protege un único recurso.
En este caso, tomamos como atributos privados del monitor una var. bool. busy inicializada en F, y una condvar nonBusy, y los métodos acquire y release.
Por otro lado, tambien podemos implementar un semaforo a partir de monitores.
IRR
Cuando un proceso ejecuta signalC, desbloquea a un proceso que estaba trabado en un waitC. A partir de ese momento, hay dos procesos que pueden ejecutar código en un monitor, pero por definición solamente uno de ellos puede hacerlo. Además puede haber procesos bloqueados en la entrada al monitor. Es imprescindible entonces establecer un orden de prioridades. Sean los procesos E, S y W los procesos que están esperando para entrar al monitor, los que terminator de ejecutar signal y los que fueron liberados de la wai condition respectivamente, en primer lugar notemos que no tiene sentido que E sea mayor a S o W, ya que podría suceder que procesos nuevos entren al monitor, pero no puedan operar en él debido a que los viejos no lograron salir aun, ocasionando starvation. Los monitores clásicos establecen el orden E < S < W. Sin IRR habría que re-chequear la condición luego de salir del waitC. La desventaja de IRR es que puede suceder que la concurrencia en algún momento no sea máxima.
Problemas
- implementación con semáforo. Se necesita un semáforo para el monitor. Se necesita un semáforo y un contador por condition variable.
- prod/cons. buff: array of int. notFull, notEmpty: condvars.
- L/E. startRead, endRead. startWrite, endWrite. #readers, #writers: int(0). okToRead, okToWrite: condvars.
- filo.
implementación de monitor con semáforo.
Se necesita un semáforo para el monitor. Se necesita un semáforo y un contador por condition variable.
prod/cons. con monitores
buff: array of int. notFull, notEmpty: condvars.
L/E. con monitores
startRead, endRead. startWrite, endWrite. #readers, #writers: int(0). okToRead, okToWrite: condvars.
filo con monitores
un monitor por filo que indica cuantos tenedores tiene disponibles.
Redes de Petri
Redes de Petri.
Una Red de Petri es una representación matemática o gráfica de un sistema distribuido. La red de Petri esencial fue definida en la década de los años 1960 por Carl Adam Petri. Son una generalización de la teoría de autómatas que permite expresar un sistema a eventos concurrentes.
Una red de Petri es un grafo dirigido bipartito que tiene dos tipos de nodos, los estados y las transiciones, que se denotan como círculos y rectángulos rellenos respectivamente. Un estado puede contener cualquier cantidad de fichas o marcas, que se representan con puntos negros. Una transición queda habilitada si todos los estados entrantes tienen por lo menos una marca.
Se puede tomar también una definición más general de redes de Petri que adhieren a lo presentado un peso a cada arista. De esta forma, una transición queda habilitada únicamente si cada nodo entrante tiene una función marca mayor o igual al peso del arco que lo conecta con la transición.
En cualquier caso, cuando se produce una transición, todos los nodos entrantes descuentan en su función marca una cantidad equivalente al peso de la arista que los conecta con la transición. Del mismo modo, a cada nodo de salida se le suman marcas de acuerdo al peso de la arista que lo conecta con la transición.
Problemas con Redes de Petri y sus soluciones.
- (a+b)/(a-b)
- Porudctor/consumidor
- Porudctor/consumidor con buff. acotado
- cliente/servidor