1 Exclusión mutua

Anuncio
Programación Concurrente
1 Exclusión mutua
Exclusión mutua
Definición del problema: Dos procesos comparten un recurso. El acceso a dicho recurso debe ser exclusivo.
Existen dos soluciones alternancia y el Algoritmo de Dekker.
Alternancia
Consigue la exclusión mutua. Los accesos al recurso son de manera estrictamente alternada.
PROGRAM Alternancia
VAR turno: [1..2]
PROCEDURE P1;
BEGIN
REPEAT
WHILE turno = 2 DO; (*espera*)
Uso del recurso
Turno := 1;
Otras acciones
FOREVER
END;
PROCEDURE P2;
BEGIN
REPEAT
WHILE turno = 1 DO; (*espera*)
Uso del recurso
Turno := 2;
Otras acciones
FOREVER
END;
COBEGIN
P1; P2;
COEND
END;
La solución por alternancia tienen el defecto de que los accesos al recurso son estrictos en su alternancia de
manera que si un proceso necesita más el recurso deberá esperar hasta que el otro lo use, esto es debido a la variable
turno, que es la que sincroniza ambos procesos. La solución obvia parece ser utilizar dos variables que indiquen si el
proceso está usando el recurso o no, de forma que antes de usarlo, el proceso compruebe si está siendo utilizado, y en
caso de poder usar el recurso indica que lo usa él.
Esta solución conduce a una falta de exclusión mutua ya que ambos procesos pueden comprobar que el otro no
usa el recurso e intentar acceder simultáneamente al mismo. Esto se produce por que realiza primero la comprobación
del uso del recurso por parte del otro recurso y luego se modifica su variable.
Esto se podría intentar solucionar indicando primero que se quiere acceder al recurso y comprobar luego que el
mismo está libre, lo que nos lleva a una espera infinita, que se puede solucionar mediante un tratamiento de cortesía,
cuando un proceso ve que el otro quiere usar el recurso le cede turno. Esto nos puede conducir a que los procesos se
queden de manera indefinida cediéndose el paso.
La solución a la exclusión mutua la proporciona el algoritmo de Dekker. Se utilizan tres variables, las dos que
indican el deseo de uso del recurso más una tercera que indica a quien se le concede el recurso en caso de conflicto.
Este algoritmo generalizado para N procesos sólo tiene interés teórico ya que consume mucho tiempo para conseguir la
exclusión mutua.
Página 1
Programación Concurrente
PROGRAM Algortimo_de_Dekker
VAR Recurso_1, Recurso_2 (Usado, No_Usado);
Turno [1..2];
PROCEDURE P1;
BEGIN
REPEAT
Recurso_1 := Usado;
WHILE Recurso_2= Usado DO;
IF Turno=2 THEN
BEGIN
(*tratamiento de cortesia*)
Recurso_1:= No_Usado;
WHILE turno = 2 DO (*espera*)
Recurso_1:= Usado;
END;
Uso del recurso
Turno := 2;
Recurso_1:= No_Usado;
Otras acciones
FOREVER
END;
PROCEDURE P2;
BEGIN
REPEAT
Recurso_2 := Usado;
WHILE Recurso_1= Usado DO;
IF Turno=2 THEN
BEGIN
(*tratamiento de cortesia*)
Recurso_2:= No_Usado;
WHILE turno = 2 DO (*espera*)
Recurso_2:= Usado;
END;
Uso del recurso
Turno := 1
Recurso_2:= No_Usado;
Otras acciones
FOREVER
END;
BEGIN
Recurso_1:= No_Usado;
Recurso_2:= No_Usado;
Turno:=1
COBEGIN
P1;P2;
COEND;
END;
Página 2
Programación Concurrente
2 Herramientas para manejar la concurrencia
Región crítica
Varios procesos concurrentes pueden compartir una misma variable, por consistencia se debe evitar que
mientras un proceso accede a una variable el otro la modifique, es decir, se debe conseguir la exclusión mutua de los
procesos respecto a la variable compartida. Los criterios de corrección de la exclusión son los siguientes:
1. Exclusión mutua con respecto al recurso
2. Cuando existen N procesos con acceso al recurso, se le concede acceso a uno en un tiempo finito.
3. Se libera el recurso en un tiempo finito.
4. No existe espera activa.
El algortimo de Dekker conlleva espera activa de los procesos lo que provoca perdidas de eficiencia en el
procesador. Para conseguir la exclusión mutua se usa la región crítica (RC). La semántica de la RC establece que:
• Los procesos concurrentes sólo pueden acceder a las variables compartidas dentro de sus
correspondientes RC.
• Un proceso que quiera entrar a una RC lo hará en tiempo finito.
• En un instante t sólo un proceso puede estar dentro de la RC de una variable.
• Un proceso abandonará la RC en tiempo finito.
Con estas cuatro características se puede asegurar que:
1. Si el número de procesos dentro de una RC es 0 el proceso que lo desee puede entrar.
2. Si el número de procesos dentro de una RC es 1 el proceso que lo desee debe esperar.
3. Cuando un proceso sale de RC se permite que entre uno de los que esperan.
4. Las decisiones de quien entra y cuando abandona una RC se tomará en tiempo finito.
5. Se supone que la cola de espera es justa y pasiva.
En PASCAL una RC se define:
...
VAR v: SHARED tipo;
...
PROCEDURE P1;
BEGIN
...
REGION v DO acción con v
...
END
...
Semáforos
Si tenemos varios procesos que deban trabajar de forma sincronizada se precisa un nuevo constructor, el
semáforo. El semáforo es un tipo abstracto de datos caracterizado por:
• Estructuras de datos:
- Contador entero positivo
- Cola de procesos esperando por ese semáforo.
• Siendo s: semaforo, se pueden realizar las siguientes operaciones:
- WAIT (s);
- SIGNAL (s)
- INIT (s, valor)
WAIT y SIGNAL se excluyen en el tiempo. La operación INIT sólo está permitida en el cuerpo del programa.
El comportamiento de estas operaciones es:
WAIT (s)
-
Si contador = 0, se lleva la proceso que hizo la operación a la cola asociada con el
semáforo s. Abandona el procesador a favor de otro proceso.
Si contador > 0, se decrementa en 1 y el proceso continúa ejecutándose.
Página 3
Programación Concurrente
SIGNAL (s)
- Si contador > 0, se incrementa en 1 y el proceso continúa.
- Si contador = 0 y hay procesos esperando, se toma uno y se pone en estado de preparado
para ejecutarse, el proceso que ejecutó la operación continúa.
INIT (s, valor_inicial):
- Pone el contador al valor indicado.
Región crítica condicional
Permite evitar el gasto de recursos que supone la espera activa de un proceso que espera una condición B que
debe satisfacer una variable compartida v. La programación de una RCC es la siguiente:
PROCEDURE P1
BEGIN
...
REGION v DO
AWAIT condición;
...
END
...
END;
La diferencia con una RC es la sentencia AWAIT. Esta primitiva sólo puede estar dentro de una RC, si hay
varias RC anidadas, AWAIT se asocia con la más próxima. Esta sentencia produce una espera pasiva y su
funcionamiento es el siguiente:
- Si condición = TRUE el proceso continúa por la siguiente sentencia.
- Si condición = FALSE el proceso detiene su ejecución y abandona la RC pasando a una
cola de espera Qs asociada con la RC.
El proceso no vuelve a entrar en la RC hasta que otro proceso la abandona, es decir, cuando haya probabilidad
de que ‘condición’ haya cambiado.
Una RC tiene dos colas asociadas:
• Qv : Cola de espera a una RC ocupada, es la cola de entrada a RC.
• Qs : Cola de espera de los procesos que esperan un cambio en AWAIT.
Buzones
Los buzones se utilizan para comunicar dos procesos, la sintaxis es:
VAR
Identificador
:
Buffer
Max
of
Mensaje
Identificadores es el nombre de la variable buzón. La constante máximo indica la capacidad del buzón. Es
decir, el máximo número de mensajes que puede albergar el buzón. El tipo mensaje, indica el tipo de mensajes que
puede almacenar un buzón.
El buzón es un tipo abstracto de datos compuesto por una estructura de datos y un conjunto de operaciones
asociadas a tal estructura. Las operaciones que se realizan sobre un buzón son:
SEND (mensaje, B):
- Si el buzón B no está vacío, deja el mensaje y continua.
- Si el buzón B está lleno, espera que halla un hueco, el proceso pierde el procesador.
RECEIVE (mensaje, B):
- Si el buzón B no está vacío, recoge el mensaje y continua.
- Si el buzón B está vacío, espera un mensaje.
Ambas operaciones se excluyen en el tiempo, son regiones críticas respecto del buzón. La semántica de los
buzones implica las siguientes reglas de sincronización:
1. El productor no puede superar la capacidad del buzón
2. El consumidor no puede consumir mensajes más rápidamente de lo que se producen.
3. El orden en el que se consumen los mensajes es el mismo en el que se producen.
Página 4
Programación Concurrente
Los buzones así definidos tienen un comportamiento bloqueante, hay situaciones en las que esto no es
deseable, la implementación de un buzón no bloqueante es:
TYPE buzon_NO_bloqueante = SHARED RECORD
Buffer: ARRAY [0..max-1] OF T
p, c : 0..max-1;
lleno : 0..max;
END;
PROCEDURE Enviar (mensaje:T; VAR b:buzon_NO_bloqueante; VAR hecho: BOOLEAN)
BEGIN
REGION b DO
IF lleno = max THEN hecho : = FALSE
ELSE BEGIN
buffer(p) := mensaje;
p:= (p+1) mod max;
lleno := lleno + 1;
hecho := TRUE;
END
END
PROCEDURE Recibir (VAR mensaje :T; VAR b: buzón_NO_bloqueante;
VAR hecho:BOOLEAN);
BEGIN
REGION b DO
IF lleno = 0 THEN hecho : = FALSE
ELSE BEGIN
mensaje:= buffer(c);
c:= (c+1) mod max;
lleno := lleno - 1;
hecho := TRUE;
END
END
En esta implementación es responsabilidad del usuario del buzón decidir que hacer cuando la
operación no se puede realizar.
Existen aplicaciones que emplean buzones cuyo comportamiento es una combinación de bloqueante y
no bloqueante, son los llamados buzones con time-out, en los que se indica el tiempo máximo que la operación
puede bloquear el proceso.
Sucesos
Los sucesos son una herramienta que permite conseguir una gestión explícita de la cola de entrada o una RC
diciendo quien puede entrar o quien no. Un suceso debe ir siempre asociado a una RC. La sintaxis es:
VAR
Identificador
:
Event
Variable
compartida
Se puede declarar un suceso ev asociado a la variable compartida v como:
VAR v : SHARED RECORD
...
ev : EVENT v
END;
El suceso es un tipo abstracto de datos compuesto por una estructura de datos (una cola) y que soporta las
siguientes operaciones:
AWAIT (ev):
El proceso que ejecuta esta operación abandona la RC donde se ejecutó, pasa a la cola del suceso ev asociado
con dicha RC y se suspende, cediendo el procesador a otro proceso.
Página 5
Programación Concurrente
CAUSE (ev):
Los procesos encolados en este proceso pasan a la cola principal de la RC y entraran en la misma cuando esté
libre. Si no hay nadie en la cola del suceso esta operación no tiene efecto. En cualquier caso, el proceso que ejecuto la
CAUSE continúa.
Las dos operaciones anteriores son excluyentes en el tiempo y sólo se pueden ejecutar dentro de una RC. Puede
haber varios sucesos asociados a una misma variable compartida. Si hay N sucesos, existen N+1 colas. Con esto el
suceso se programa:
VAR v: SHARED RECORD
Recurso_disponible
Recurso_pedido
Turno : Event
...
END;
PROCEDURE Pide (..)
BEGIN
...
REGION v DO BEGIN
WHILE no haya recursos disponibles DO BEGIN
Pedir recurso
AWAIT (Turno);
END
Toma recurso
END
PROCEDURE Produce ()
...
BEGIN
REGION
IF hay recursos disponibles THEN BEGIN
Libera recurso
CAUSE (Turno)
END
END
END
Se puede implementar una RCC utilizando sucesos. El constructor:
REGION v DO BEGIN
S1;
AWAIT B;
S2;
END
Se puede sustituir por
REGION v DO BEGIN
S1
WHILE NOT B DO AWAIT ($ev1);
S2
CAUSE ($ev1);
END
Monitores
Un monitor es un mecanismo que permite compartir de una manera fiable y efectiva tipos abstractos de datos
entre procesos concurrentes. Un monitor proporciona:
- Abstracción de datos
- Exclusión mutua y mecanismos de sincronización entre procesos
Página 6
Programación Concurrente
Abstracción de los datos
Un tipo abstracto de datos se caracteriza por un conjunto de declaraciones de variables cuyos valores definen el
estado de una instancia de ese tipo, y por un conjunto de operaciones que actúan sobre dichas variables, en PASCAL
esta estructura se consigue mediante la definición de una clase. Las variables declaradas en el interior sólo pueden ser
accedidas mediante procedimientos declarados en la clase. Para diferenciar los procedimientos privados de la clase y los
externos, a estos últimos se les añade la palabra reservada entry.
Las clases se inicializan una sola vez a través de la sentencia init y sus variables locales permanecen todo el
programa.
Exclusión mutua y sincronización
Además de la abstracción un monitor garantiza que el número de procesos que en un instante de tiempo están
ejecutando el código del monitor es como máximo uno. Además el monitor proporciona un mecanismo de
sincronización entre procesos, el constructor queue. Un procedimiento monitor puede retrasar a un proceso durante una
cantidad arbitraria de tiempo ejecutando una operación delay sobre una variable del tipo queue.
En un instante de tiempo sólo un proceso puede estar esperando en una queue. Cuando un proceso es retrasado
por la operación delay, pierde el acceso al monitor (lo abandona) y suspende hasta que otro proceso lo reanude con una
operación continue sobre la variable queue en la que se retrasó el primero. Si se permite que existan varios procesos
encolados en una queue la operación continue despertará a uno de ellos dependiendo de la política de gestión:
- FIFO: Evita el lockout
- Mas prioridad: La operación delay precisa un parámetro adicional, puede provocar
lockout.
El ejemplo más claro del uso de monitores es el productor consumidor.
PROGRAM Productor_Consumidor
TYPE buffer = monitor (capacidad: INTEGER);
(* implementa un buffer*)
VAR contenido : ARRAY [0..MAX-1 ] OF TIPO
in, out : 0...MAX-1;
Cuantos_Hay : 0...MAX;
pro, con : queue;
(*...*)
PROCEDURE lleno (): BOOLEAN;
BEGIN
RETURN Cuantos_Hay = Capacidad;
END
(*------------------------------*)
PROCEDURE vacio (): BOOLEAN;
BEGIN
RETURN Cuantos_Hay=0;
END;
(*------------------------------*)
PROCEDURE entry manda (mensaje:tipo)
BEGIN
IF lleno THEN delay (pro)
contenido [in] : = mensaje
in : = (in+1) mod capacidad;
Cuantos_Hay : = Cuantos_Hay + 1
IF Cuantos_Hay = 1 THEN continue (con)
END
(*-----------------------------*)
Página 7
Programación Concurrente
PROCEDURE entry recibe (mensaje:tipo)
BEGIN
IF vacio THEN delay (con)
mensaje : = contenido [in]
out : = (out+1) mod capacidad;
Cuantos_Hay : = Cuantos_Hay - 1
IF Cuantos_Hay = (capacidad-1) THEN continue (por)
END
(*-----------------------------*)
BEGIN
in : = 0 ; out : = 0 ; Cuantos_Hay : =0;
END (* del monitor*)
VAR Buzon : Buffer;
PROCEDURE productor
VAR m: Tipo;
BEGIN
REPEAT
Elaborar mensaje (m)
Buzon.manda (m);
UNTIL fin
END;
(*-------------------------*)
PROCEDURE Consumidor
VAR m : Tipo;
BEGIN
REPEAT
Buzon.recibe (m);
Trabajar mensaje (m);
UNTIL fin
END;
(*-------------------------*)
BEGIN (* productor consumidor *)
Init Buzón(20);
COBEGIN
Productor
Consumidor
COEND
END;
Sincronización por rendez-vous
Rendez-vous significa sincronización e intercambio de información entre dos tareas (procesos en ADA) dadas,
el hecho de establecerse rendez-vous se conoce como cita de tareas.
Las tareas cuando interactúan primero se sincronizan y luego intercambian información y finalmente
continuaran sus actividades por separado. Una tarea contiene puntos de sincronización llamados puntos de entrada. La
sincronización entre dos tareas ocurre cuando una tarea llama a un punto de entrada y la otra la acepta estableciendo
rendez-vous. La espera de las tareas cuando efectúan o esperan una cita es pasiva.
La estructura de una tarea en ADA es la siguiente:
Task Tarea is
-- declaración de puntos de entrada
Especificación
-- otras declaraciones
(interfaz)
end Tarea
Task body Tarea is
begin
-- implementación de las citas
-- en los puntos de entrada
-- otras cosas
end Tarea
Cuerpo (Parte oculta)
Página 8
Programación Concurrente
3 Interbloqueos
Definición de interbloqueo
En un entorno de multiprogramación varios procesos compiten por un número finito de recursos. Si un proceso
pide un recurso que en ese momento no está disponible entra en espera. Si el proceso A tiene el recurso R1 y espera el
R2, mientras que el proceso B tiene el recurso R2 y espera el R1, ninguna de las dos peticiones podrá ser satisfecha y
ambos procesos se bloquearán.
Un término relacionado con el interbloqueo es la inanición (starvion) que denota el estado en que uno o varios
procesos son retrasados indefinidamente en el acceso a un recurso a favor de otros.
Ejemplos de interbloqueos
Suponiendo siempre una situación
COBEGIN
P1; P2
COEND;
Regiones críticas
P1
...
...
REGION r DO BEGIN
...
REGION s DO BEGIN
...
END (s)
...
END (r )
P2
...
...
REGION s DO BEGIN
...
REGION r DO BEGIN
...
END ( r)
...
END (s)
Semáforo en el interior de una región crítica.
VAR r: SHARED ...;
S: SEMAPHORE; (* INIT (s,0)*)
P1
...
...
REGION r DO BEGIN
...
WAIT(s);
...
...
END
P2
...
...
REGION r DO BEGIN
...
SIGNAL (s)
...
...
END
Con Región Crítica Condicional.
VAR r: SHARED RECORD
C1, C2: BOOLEAN (*INIT FALSE*)
END;
P1
...
...
REGION r DO BEGIN
...
C1:=TRUE;
AWAIT C2
...
END;
P2
...
...
REGION r DO BEGIN
...
AWAIT C1
C2 := TRUE;
...
END;
Página 9
Programación Concurrente
Con semáforos
VAR SEMAPHORE; (*INIT (s,0)*)
P1
...
...
WAIT (s)
...
SIGNAL (s)
...
END;
P2
...
...
WAIT (s);
...
SIGNAL (s);
...
END;
Con buzones
VAR b1, b2: buffer 3 OF INTEGER;
P1
...
...
FOR i : = 1 TO 4 DO
SEND (m,b1)
...
FOR i : = 1 TO 4 DO
SEND (m,b2)
...
END;
P2
...
...
FOR i : = 1 TO 4 DO
RECEIVE (m,b2);
...
FOR i : = 1 TO 4 DO
RECEIVE (m,b1);
...
END;
Con sucesos
VAR v: SHARED RECORD
...
sc : EVENT r
END;
P1
REGION r DO BEGIN
...
CAUSE(sc);
...
AWAIT C2
...
END;
P2
REGION r DO BEGIN
...
AWAIT (sc);
...
CAUSE (sc);
...
END;
Recursos
La secuencia de operaciones para usar un recurso son:
-
Pedir recurso. Si no está disponible el proceso se bloquea.
Utilización del recurso.
Liberación del recurso.
Tanto la petición como la liberación del recurso son llamadas al sistema operativo, que es el que mantiene el
estado de cada uno de ellos. Se puede distinguir entre recursos permanentes y temporales. Un proceso permanente
puede ser utilizado repetidamente por muchos procesos (dispositivos físicos). Un proceso temporal es producido por un
proceso y consumido por otro (mensajes).
Definición y caracterización de los interbloqueos
Un conjunto de procesos está interbloqueado si cada proceso en el conjunto está esperando por un suceso que
solamente puede producir otro proceso del conjunto. Puesto que todos los procesos esperan, ninguno de ellos podrá
producir el suceso que despierte a cualquiera de los otros miembros del conjunto.
Página 10
Programación Concurrente
Condiciones necesarias.
Los interbloqueos se previenen asegurando que no se cumple nunca una o más de las condiciones siguientes:
-
Exclusión mutua: cada recurso o bien está disponible o bien asignado a un único proceso.
Asignación parcial: Un proceso puede adquirir sus recursos por partes.
Programación no expulsora: Un recurso sólo puede ser liberado por el proceso que lo ha
adquirido.
Espera circular: Debe existir un conjunto de procesos esperando (P0, P1, ...,Pn) tal que
P0 está esperando un recurso que tiene P1, P1 uno que tiene P2;...P(n-1) espera uno que
tiene Pn y Pn el de P0.
Grafos de asignación de recursos
Los interbloqueos se pueden describir mediante un grafo dirigido, el grafo de asignación de recursos de
sistema. El grafo está compuesto por un conjunto de nodos compuestos por los procesos y un conjunto de arcos
dirigidos que unen procesos y recursos. Los procesos se representan mediante círculos, los recursos mediante
rectángulos. Un arco dirigido de Pi a Ri indica que Pi está bloqueado esperando Ri. Si el arco está dirigido de Ri a Pi
significa que Pi tiene asignado el recurso Ri.
Si cada recurso tiene una instancia la existencia de un ciclo en el grafo es condición necesaria y suficiente para
que exista interbloqueo. Si cada recurso tiene varias instancias, un ciclo no implica necesariamente la existencia de un
interbloqueo.
Estrategias para tratar los interbloqueos
Ignorar el problema.
Evidentemente es la solución más simple, se puede defender desde el punto de vista económico de intentar
tratarlos si se van a producir pocos.
Asegurar que el sistema nunca entra en estado de interbloqueo.
Se trata de imponer restricciones a los procesos para que los interbloqueos no puedan producirse, existen dos
métodos:
- Prevenir los interbloqueos, es decir, asegurar que no se producen.
- Evitar los interbloqueos
Técnicas para prevenir los interbloqueos
Están basadas en que no se lleguen a producir las condiciones necesarias para que se produzca un interbloqueo.
Exclusión mutua.
La exclusión mutua debe mantenerse para tipos de recursos no compartibles, ya que los compartibles no
pueden verse envueltos en un interbloqueo. En general, no es posible eliminar la exclusión mutua.
Asignación parcial.
Para eliminar esta condición se debe asegurar que cuando un proceso solicite un recurso no tenga asignado
otro. Existen dos protocolos:
- Asignación total: El proceso antes de ejecutarse solicita todos los recursos que precisa. Si
estos están disponibles el proceso se ejecuta hasta terminar y los libera. Si no están
disponibles el proceso se espera a que lo estén. El problema es que muchos procesos no
conocen a priori que recursos precisan, además los recursos no se administran de manera
óptima.
- Un proceso puede solicitar recursos sólo cuando no tenga otros asignados, antes de
solicitar cualquier recurso debe liberar los que tiene asignados.
Ambas soluciones padecen un posible starvation, inanición.
Programación no expulsora.
Eliminar esta condición significa obligar a los procesos a que liberen sus recursos temporalmente a favor de
otros procesos. Para ello se puede seguir este protocolo:
Si un proceso que tiene asignado un número determinado de recursos pide otro(s) que no se le puede(n) asignar
inmediatamente, libera todos los recursos asignados. El proceso arranca cuando se le asignan todos los procesos que
necesita.
Página 11
Programación Concurrente
Otro método es comprobar si el recurso necesario está disponible, entonces se asigna, por el contrario, si lo
tiene otro proceso se comprueba si éste está esperando otro recurso, en cuyo caso se expulsa el recurso asignándose al
proceso que lo pedía. Si el recurso no está disponible ni está asignado a un proceso bloqueado, el proceso solicitante se
suspende. Mientras se mantenga en este estado los recursos que dispone se le pueden quitar. El proceso se reanuda
cuando disponga del recurso que solicitó y de todos aquellos que se le hayan quitado mientras estaba bloqueado.
La expulsión no es práctica en los dispositivos que necesitan intervención del operador como son los discos,
cintas, etc.
Espera circular.
La espera circular se puede eliminar imponiendo una ordenación lineal de los tipos de recursos. Todo proceso
puede pedir recursos siempre que lo desee, pero todas las peticiones deben realizarse en orden numérico creciente. Es lo
que se denomina asignación jerárquica de recursos. Con estas suposiciones no puede ocurrir interbloqueo, una petición
de recursos al nivel más alto Lmax, no puede ser retrasado por peticiones de otro nivel superior por que este no existe,
cuando esta liberación se produzca, se libera para Lmax-1. El punto débil es que puede llegar a ser imposible encontrar
una ordenación que satisfaga a todos los usuarios.
Técnicas para evitar los interbloqueos
En los sistemas en los que no se pueden eliminar las condiciones que evitan los interbloqueos se debe de tener
alguna información adicional sobre los recursos que utilizará el proceso. El modelo más sencillo y utilizado es exigir
que cada proceso diga antes de ser arrancado, cuantos recursos necesitará a lo largo de su ejecución. El algoritmo más
utilizado para evitar los interbloqueos es el denominado ‘algoritmo del banquero’, que generalizado a n recursos,
sabiendo las necesidades máximas por adelantado se construyen dos tablas, la de recursos asignados y la de necesidades
de recursos.
Dada una petición de recursos, el algoritmo simula concederla y comprueba si esto lleva a una situación segura
o no de la siguiente manera
A
B
C
D
E
Recursos asignados
R1 R2 R3 R4
3
0
1
1
0
1
0
0
1
1
1
0
1
1
0
1
0
0
0
0
Recursos existentes :
Recursos asignados:
Recursos disponibles:
1.
2.
3.
Necesidades de recursos
R1 R2 R3 R4
A 1
1
0
0
B 0
1
1
2
C 3
1
0
0
D 0
0
1
0
E 2
1
1
0
E : (6,3,4,2)
A: (5,3,2,2)
D: (1,0,2,0)
Buscar en la tabla ‘necesidades de recursos’, una fila R cuyas necesidades de recursos son más pequeñas
que el vector D. Si esta fila no existe indica que el sistema está interbloqueado.
Encontrada la fila R, se supone que el proceso de esa fila pide todos los recursos, termina y los libera
sumándose dichos recursos al vector D.
Se repite 1 y 2 hasta que los procesos terminan, situación segura, o se produce interbloqueo, situación
insegura.
El algoritmo del banquero en la práctica no es factible por:
- Coste en tiempo de ejecución.
- Pocos procesos conocen sus necesidades máximas a priori
Permitir los interbloqueos
Si el sistema no emplea ningún protocolo para evitar los interbloqueos, debe implementar un esquema de
detección y recuperación de los mismos. En esta técnica, el sistema monitoriza las peticiones y liberaciones de recursos.
Cada vez que se concede o libera un recurso, se actualiza el grafo de recursos y se comprueba si existe interbloqueo o
no. Si existe se elimina uno de los procesos que intervienen, si el problema no se soluciona eliminamos otro, así hasta
que se elimine el interbloqueo.
Página 12
Programación Concurrente
Interbloqueos con recursos temporales.
Varios procesos productores y consumidores conectados a un único buzón no pueden interbloquearse, pero si
se conectan circularmente varios procesos mediante buzones puede existir interbloqueo. Para evitar la circularidad se
puede jerarquizar los procesos en niveles. Cada proceso pertenece a un nivel Li. Los procesos de niveles inferiores se
denominan maestros y pueden proporcionar mensajes (‘peticiones’) a los procesos de niveles superiores, seguidores.
Estos pueden responder (‘replicas’) a sus maestros en contestación a sus peticiones. Con esta configuración las
peticiones se envían en un sentido y las respuestas en el contrario.
Peticiones
.......
P1
Pn-1
P2
Pn
.........
Respuestas
A pesar de esta jerarquía el sistema aún puede interbloquearse. Dos procesos P y Q pueden ser incapaces de
mandar mensajes y respuestas porque ambos buzones estén llenos o ser incapaces de recibirlos si los buzones están
vacíos, con lo que quedarían interbloqueados.
P
Q
La regla que soluciona el problema es “no intentar mandar un mensaje o respuesta a menos que alguien lo
vaya a recibir; o no intentar recibir un mensaje o respuesta al menos que alguien lo vaya a mandar”. Con esta solución
no existen interbloqueos con comunicación de procesos jerarquizados.
1. La hipótesis es cierta para cualquier proceso Pj del nivel más alto (j=max) ya que no existen
seguidores que lo puedan retrasar.
2. Un proceso Pi-1 del nivel Li-1 satisface la hipótesis si no es retrasado indefinidamente por un
seguidor Pj de un nivel superior, tenemos dos posibilidades:
- Pi-1 es incapaz de mandar un mensaje a un seguidor Pj porque el buzón está lleno. Según
la hipótesis el seguidor recibirá finalmente el correspondiente mensaje y permitirá seguir
a Pi-1.
- Pi-1 es incapaz de recibir una respuesta de un seguidor Pj porque un buzón está vacío,
según la hipótesis el seguidor del nivel Lj (j ≥ i) recibirá el mensaje y producirá la
respuesta que permita continuar a Pi-1.
3. Por inducción se demuestra que se cumplen de L1 a Lmax
Página 13
Descargar