Sunteți pe pagina 1din 17

CAPITULO 8: DEADLOCKS

En un ambiente de multiprogramación, varios procesos pueden competir por un numero finito de


recursos. Un proceso solicita recursos y si estos no están disponibles en ese momento, el proceso entra
en estado de espera.

Puede ocurrir que procesos en espera nunca cambien de estado, pues los recursos que han solicitado
han sido tomados por otros procesos en espera. Por ejemplo, en un sistema con 4 unidades de cinta y 2
procesos, cada uno de los cuales ha tomado 2 unidades de cinta pero necesitan 3, cada uno de ellos
esperara que el otro libere las cintas. Esta situación se conoce como deadlock (abrazo mortal).

Un sistema debe tomar acciones extremas para provenir un deadlock o recuperarse si ello sucede, tales
como liberación de todos los recursos de uno o mas procesos que han entrado en deadlock. En este
Capitulo se describen algunos de los varios métodos que los S.O. pueden usar para manejar el problema
de los deadlocks.

8.1. EL PROBLEMA DEL DEADLOCK (ABRAZO MORTAL)

Este problema no es único de los S.O. Generalizando la interpretación de recursos y procesos, tenemos
situaciones de deadlock en nuestra vida diaria. Por ejemplo, consideremos el cruce de un río a través de
piedras. Para cruzarlo, una persona (en nuestro ejemplo un proceso) debe pisar una a una las piedras
(recursos). Si dos personas de ambos lados del río comienzan el cruce, al llegar a la mitad se produce el
deadlock.

Una solución seria que una de ellas retroceda. Esto, en el ambiente de S.O. se denomina rollback. Si
varias personas son las que cruzan, para solucionar el problema, puede que sea necesario que mas de
una de ellas retrocedan. La única manera de asegurar que el deadlock no ocurra, es poniéndose de
acuerdo en un protocolo. Por ejemplo para iniciar el cruce se vea que de la otra orilla nadie ya lo ha
iniciado. Debemos hacer algunas observaciones a este protocolo:

* Se debe determinar un mecanismo para saber si alguien este cruzando, el río. Si es posible saber el
estado de todas las piedras, esta sola condición es suficiente, pero si no (por ejemplo que el río sea muy
ancho o no se divise la otra orilla) debo implementar otro mecanismo.

* Supongamos que simultáneamente 2 personas de orillas opuestas quieran cruzar el río. Nuestro
protocolo no especifica que se debe hacer. Si ambos cruzan, tengo deadlock. Si cada una espera por la
otra a comenzar, estamos también en otra forma de deadlock. Una solución seria asignar a una de las
orillas mayor prioridad: por ejemplo la persona de la costa Este cruzara primero, mientras la otra deberá
esperar.

* Si aplicamos lo anterior, una o mas personas pueden esperar indefinidamente para cruzar. Esta
situación se conoce como inanición. Sería el caso que una fila continua de gente cruce del Este (de
mayor prioridad). Para evitar esto debo extender mi protocolo. Por ejemplo, definiendo un algoritmo que
alterne la dirección de cruce.

8.1.1. MODELO DE UN SISTEMA

Un sistema consiste en un numero finito de recursos a ser distribuidos entre un numero de procesos en
competencia. Los recursos se particionan en distintos tipos, cada uno de los cuales se llaman
"Instancias".

Como ejemplo de tipos de recursos tengo ciclos de CPU, espacio de memoria, archivos, dispositivos de
E/S (impresoras, unidades de cintas etc.).
Si el sistema tiene 2 CPU, entonces este tipo de recurso tiene 2 instancias. Si un proceso solicita una
instancia de algún tipo de recurso, la asignación de cualquier instancia satisface el pedido. Sí no sucede
así, entonces las instancias no son idénticas, y por lo tanto no han sido definidas correctamente las
clases de tipo de recursos. Por ejemplo, si un sistema tiene 2 impresoras, estas pueden definirse dentro
del mismo tipo de recurso, si es indiferente por donde se imprima una salida. Sin embargo, si una
impresora esta en el piso 9 y la otra en el sótano de un edificio, evidentemente los usuarios del piso 9 no
verán ambas impresoras como equivalentes y por lo tanto debo definir ambas como distintos tipos de
recursos.

Un proceso debe solicitar un recurso antes de usarlo, y liberarlo luego. El proceso puede solicitar tantos
recursos como requiera la tarea a realizar.

Obviamente, el numero de recursos solicitados no puede superar el numero de recursos disponibles en el


sistema.

Bajo condiciones normales de trabajo, un proceso puede utilizar un recurso solo en la secuencia
siguiente:

1.- Pedido o solicitud: si el pedido no puede ser cumplido (por ejemplo por estar siendo usado por otro
proceso, el proceso debe esperar hasta que este disponible.
2.- Uso: El proceso puede operar el recurso.
3.- Liberación: El proceso libera el recurso.

El pedido y liberación de recursos son llamadas al sistema. Ejemplos: Asignación / Liberación de


memoria, Apertura / Cierre de archivos, Pedido / Liberación de dispositivos.

El uso de los recursos solamente se realiza a través de llamadas al sistema (por ejemplo leer o escribir
un archivo o dispositivo de E / S). Por lo tanto, en cada pedido de uso, el SO chequea que el proceso
haya pedido el recurso y se le haya asignado el mismo. Una tabla del sistema tiene registrado si un
recurso esta libre o no, y de no estarlo, a que proceso ha sido asignado.

Si un proceso pide un recurso que esta siendo usado por otro, entonces se agrega a una cola de
procesos en espera por ese recurso.

8.1.2. DEFINICION DE DEADLOCK

Un conjunto de procesos esta en estado de deadlock cuando cada proceso del mismo esta esperando un
evento que solo puede ser causado por otro proceso que pertenece a ese conjunto.

Los eventos que nos interesan para nuestro estudio son los de asignación y liberación de recursos del
sistema. (Otros eventos también pueden causar un deadlock). Por ejemplo, en un sistema con 3
unidades de cinta, donde existen 3 procesos, cada uno de ellos con una unidad asignada. Si cada
proceso solita una segunda unidad, los 3 procesos estarán en estado de deadlock. Este ejemplo, ilustra
procesos compitiendo por el mismo tipo de recurso. Pero también puede producirse deadlocks donde
intervengan distintos tipos de recursos. Por ejemplo un sistema con una impresora y una lectora de
tarjetas. Supongamos que el proceso P tiene asignada la lectora de tarjetas y el proceso Q la impresora.
Si P solicita la Impresora y Q la lectora, se produce un deadlock.

8.2.- CARACTERIZACION DE UN DEADLOCK

Es obvio que un deadlock no es deseable. En este estado los procesos nunca terminan su ejecución y
los recursos del sistema nunca se liberan, haciendo que otros procesos no puedan iniciar su ejecución.
8.2.1. CONDICIONES NECESARIAS

Una situación de deadlock puede producirse si y solo si las siguientes 4 condiciones se dan
simultáneamente en un sistema.

1) Exclusión mutua: al menos un recurso esta asignado en modo no compartido, es decir que solo
un proceso por vez puede usar dicho recurso. Si otro proceso solicita ese recurso, debe esperar
hasta que el recurso sea liberado.
2) Retención y espera: debe existir un proceso que tenga asignado por lo menos un recurso y este
esperando por la asignación de otros recursos adicionales que están tomadas por otros procesos.
3) Sin liberación forzada: los recursos no pueden ser "robados", es decir que un recurso solo puede
ser liberado voluntariamente por el proceso al que esta asignado, luego que este haya terminado
su tarea.
4) Espera circular: debe existir un conjunto de procesos P0, P1 ...Pn en estado de espera: P0 espera
un recurso asignado a P1; P1 espera un recurso asignado a P2 .... Pn-1 espera uno asignado a
Pn y Pn espera un recurso asignado a P0.

Remarcamos que estas 4 condiciones deben darse para un deadlock. La cuarta condición implica la
segunda, por lo que las mismas son interdependientes. Sin embargo veremos en 8.3. que es útil
considerarlas por separado.

Podemos ver las condiciones en el ejemplo del cruce del río. Un deadlock ocurre si y solo si 2 personas
que cruzan desde orillas opuestas se encuentran en el medio del río. La condición de exclusión mutua
aparece, ya que cada piedra solo puede ser pisada por una persona a la vez. La condición de retención y
espera aparece pues cada persona pisa una piedra y espera pisar la próxima piedra luego. La tercera
condición sucede, pues nadie puede remover una piedra que es pisada por la otra persona. La cuarta
condición se da pues la persona que viene del Este espera a la que viene del Oeste y viceversa. Ninguna
de las 2 puede continuar y cada una espera que la otra saque el pie de la piedra.

8.2.2. GRAFICO DE ASIGNACION DE RECURSOS

Un deadlock puede ser descripto mas precisamente usando un gráfico de asignación de recursos del
sistema. Consiste en pares G = (V , E); donde V es un conjunto de nodos y E es un conjunto de flechas.

El conjunto de nodos se divide en 2 tipos: P = (p1, p2, ... , pn), conjunto de todos los procesos del
sistema y R = (r1, r2, ... rm), conjunto de los tipos de recursos del sistema.

Cada elemento del conjunto E es un par ordenado (pi, rj) o (rj, pi).

(pi, rj) implica que el proceso pi ha solicitado una instancia del tipo de recurso rj y actualmente esta
esperando la asignación.
(rj, pi) implica que una instancia del tipo de recurso rj ha sido asignada al proceso pi.
A la primera se la llama flecha de pedido y a la segunda flecha de asignación.

Representamos los procesos como círculos y los tipos de recursos como rectángulos, donde cada
instancia aparece como un punto. Notemos que cada flecha de pedido apunta solo a un tipo de recurso
mientras que cada flecha de asignación nace de una instancia.

Del gráfico de la Fig. 8.3, puede mostrarse fácilmente que aquel que no contenga ciclos no está en
deadlock. Por el contrario, si el gráfico contiene un ciclo, entonces puede existir un deadlock. Si cada tipo
de recurso tiene exactamente una instancia, luego un ciclo implica que un deadlock ha ocurrido. Si cada
recurso tiene varias instancias, un ciclo no necesariamente implica un deadlock. Es solo una condición
necesaria pero no suficiente.

Para ilustrar este concepto, volvamos a la figura 8.3. Supongamos que el proceso p3 pido una instancia
del tipo de recurso r2. Debido a que no existe una instancia disponible, agrego una flecha (p3, r2) al
gráfico. (figura 8.4). Acá existen 2 ciclos mínimos en el grafico:
pl  r1  p2  r3  p3  r2  p1
p2  r3  p3  r2  p2

Figura 8.3. Gráfico de asignación de recursos

Figura 8.4 Gráfico de asignación de recursos con deadlock

Los procesos p1, p2 y p3 están en deadlock. El proceso p2 esta esperando por el recurso r3, el cual esta
asignado al proceso p3. Este a su vez esta esperando que p1 o p2 liberan una instancia de r2.
Adicionalmente, p1 espera que p2 libere el recurso r1.

Ahora veamos la Figura 8.5., tengo ciclo p1  r1  p3  r2  p1.

Figura 8.5. Gráfico de asignación de recursos con ciclo pero sin deadlock

Acá, sin embargo no tengo deadlock: p4 puede liberar una instancia de r2, la que será asignada a p3,
rompiendo el ciclo.

Resumiendo: en un gráfico de asignación, si no existen ciclos, no hay estado de deadlock. Si por el


contrario, hay ciclos, puede o no haber un deadlock.

8.2.3. METODOS PARA MANEJO DE DEADLOCKS

Principalmente, existen 2 métodos para el manejo de deadlocks. Podemos usar un protocolo que me
asegure que el sistema nunca entrara a un estado de deadlock.
Como alternativa, podemos permitir que el sistema entre a un estado de deadlock y luego recuperarlo.
Como se ve en 9.6. esta última alternativa puede resultar un poco dificultosa y cara. Por lo tanto, primero
veremos métodos que me aseguren la no ocurrencia de deadlocks.

Hay 2 métodos: uno de ellos previene la ocurrencia del deadlock y el otro lo evita.
8.3. PREVENCION DE DEADLOCK

Vimos que deben cumplirse 4 condiciones necesarias para un deadlock.


Asegurando que al menos una de ellas no ocurra, estoy previniendo la ocurrencia de deadlocks.

8.3.1. EXCLUSION MUTUA

Esta condición debe darse para tipos de recursos no compartidos. Por ejemplo una impresora no puede
ser asignada a varios procesos. Los recursos compartidos, por el contrario, no requieren de accesos
exclusivos y por ende no pueden provocar un deadlock. Los archivos de solo lectura son un buen
ejemplo de recurso compartido. Varios procesos pueden abrir una archivo de este tipo simultáneamente.
Un proceso nunca necesita esperar por un tipo de recurso compartido. Sin embargo, en general, no se
puede prevenir un deadlock negando esta condición de exclusión mutua ya que algunos recursos
intrínsecamente son no-compartidos.

8.3.2. RETENCION Y ESPERA

Para asegurar que esta condición nunca se cumpla un sistema, debemos garantizar que siempre cuando
un proceso pida un recurso, este no esté asignado a otro proceso. Un protocolo posible de usar requiere
que un proceso pida y se le sea asignado todos sus recursos antes de empezar a ejecutarlo. Puede
implementarse imponiendo que las llamadas al sistema de solicitud de recursos precedan a cualquier otro
tipo de llamadas.

Un protocolo alternativo seria de permitir a un proceso solicitar recursos solo si no tiene asignado
ninguno. El proceso puede requerir recursos e inmediatamente usarlos. Antes de requerir otros, debe
primero liberar todos los recursos previamente asignados.

Para ilustrar la diferencia entre estos 2 protocolos, supongamos un proceso que copia desde una lectora
de tarjetas a disco, clasifica el archivo en disco y luego imprime el resultado sobre impresora y graba en
cinta. si debo requerir todos los recursos inicialmente, tendré asignados la lectora de tarjetas, el archivo
en disco, la impresora y la cinta durante toda la ejecución, aunque por ejemplo la cinta la use solo al final.

El segundo método inicialmente solo tiene asignados las lectora de tarjetas y el archivo en disco. Luego
los libera. Pide el archivo en disco y la impresora. Luego los libera y pide el archivo en disco y la cinta.

Hay 2 grandes desventajas en estos protocolos. Primero, la utilización de recursos puede ser muy baja,
ya que muchos de los recursos asignados serán usados un corto periodo de tiempo. En el ejemplo,
podemos tomar la lectora de tarjetas y el archivo en disco, liberarlos y luego tomar el archivo en disco e
impresora, solo si estamos seguros que la información permanecerá en el disco. Si no tenemos
seguridad de ello, debemos pedir todos los recursos inicialmente en ambos casos.

Segundo, es posible que ocurra inanición. Un proceso que requiera varios recursos muy usados, puede
ser que deba esperar indefinidamente, pues al menos siempre uno de los que necesite esté asignado a
otro proceso.

8.3.3. NO EXISTENCIA DE DESASIGNACION FORZADA

La tercera condición necesaria es que no habrá desasignacion forzada de recursos una vez asignados.
Puede usarse el siguiente protocolo: si un proceso que tiene asignado recursos solicita otros no
disponibles (por lo que debe esperar), entonces todos sus recursos asignados son liberados. Estos son
agregados a la lista de recursos por los cuales el proceso espera. El proceso recomenzara cuando tenga
disponibles todos los recursos necesarios.
Como alternativa, si un proceso solicita algún recurso, primero chequeamos si está disponible. Si lo está
lo asignamos; si no, nos fijamos si el recurso requerido está asignado a algún proceso en espera de
recursos adicionales. De ser así, desasignamos el recurso y se lo damos al que lo solicita. Si no hay
disponibles, el proceso debe esperar y sus recursos asignados están disponibles por si algún proceso lo
solicita.

El proceso solo continua cuando se le asigne el recurso que necesitaba más algún recurso perdido
durante la espera.

Este protocolo se aplica para recursos que puedan ser fácilmente salvados y recuperados luego, tales
como registros de CPU y espacio de memoria.

Generalmente no se usa para impresoras, cintas, etc. Sin embargo el sistema operativo THE (1972),
permitía desasignar una impresora, y la salida de 2 procesos se mezclaban. Luego el operador separaba
las paginas.

8.3.4. ESPERA CIRCULAR

Para asegurar que la condición de espera circular nunca suceda, podemos imponer un ordenamiento de
todos los tipos de recursos. Es decir, asignamos a cada tipo de recurso un numero entero único lo que
nos permite comparar 2 recursos y determinar cual precede a cual en nuestro ordenamiento.

Dicho más formalmente, sea R (r1, r2, ... , rn) el conjunto de tipos de recursos, entonces podemos definir
una función univoca F: R --> N donde N es el conjunto de los números naturales. Por ejemplo, si el
conjunto de tipos de recursos incluye discos, cintas, lectoras de tarjetas, impresoras, etc., entonces:

F (lectoras) = 1 ; F (discos) = 5 ; F (cintas) = 7 ; F (impresoras) = 12

Ahora consideremos el siguiente protocolo para prevenir deadlocks: cada proceso solo puede requerir
recursos en numeración creciente, es decir que un proceso inicialmente pide cualquier número de
instancias del tipo de recursos ri. Luego el proceso puede requerir instancias del tipo de recursos rj, si y
solo si F ( rj ) > F ( ri ) . Si se necesitan varias instancias del mismo tipo de recurso, debe hacerse un solo
pedido por todas.

Usando la función definida anteriormente, un proceso que desea la lectora de tarjetas y el disco, debe
solicitar primero aquella y posteriormente el disco. Alternativamente, podemos requerir que cuando un
proceso necesite un tipo de recurso rj, haya liberado recursos ri, siendo F ( ri ) >= F ( rj )

Si se usan estos protocolos no puede existir espera circular. Se puede probar por el absurdo.
Supongamos un conjunto de procesos en espera circular p0, p1, ... , pn, donde pi espera un recurso rj
que esta asignado al proceso pi + 1. Debe ser F ( ri ) < F ( ri + 1 ) para todo i. Pero esto significa que
F ( r0 ) < F ( r1 ) < ... < F ( r0 ). Por transitividad F ( r0 ) < F ( r0 ) lo cual es imposible.

Recordemos que las funciones F se definirán de acuerdo al orden normal de uso de recursos en un
sistema. Por ejemplo como la lectora de tarjetas normalmente se necesita antes que la impresora, será
razonable definir F (lectora tarjetas) < F (impresora).

8.4. METODO PARA EVITAR UN DEADLOCK

Los algoritmos para prevención de deadlock vistos en 8.3, se basan en establecer restricciones a los
pedidos de recursos. Así aseguramos que al menos una de las condiciones necesarias para deadlock
nunca ocurran. Como efecto de estos algoritmos, tendremos posiblemente un uso muy reducido de los
dispositivos y baja eficiencia del sistema.
Un método alternativo de evitar deadlocks es requerir mayor información acerca de como serán
requeridos los recursos. Por ejemplo, en un sistema con una lectora de tarjetas y una impresora,
podemos averiguar que el proceso P primero solicitara la lectora y luego la impresora; las usara y liberara
ambas mas tarde. El proceso 0 pedirá la impresora primero y posteriormente la lectora.

Así, conociendo completamente la secuencia de pedidos y liberaciones de cada proceso, podemos


decidir si el proceso va a esperar o no luego de cada pedido.

Cada pedido requiere que el sistema considere los recursos actualmente disponibles, los ya asignados a
cada proceso y los pedidos futuros y liberaciones de cada proceso, para decidir si el pedido actual puede
ser satisfecho y / o esperar para evitar un deadlock.

Existen varios algoritmos, los cuales difieren en el tipo y cantidad de información que el sistema necesita.
El modelo mas simple y útil requiere que cada proceso declare el numero máximo de recursos de cada
tipo a usar. Obtenida esa información a priori para cada proceso, es posible construir un algoritmo que
asegure que el sistema nunca entrara en estado de deadlock. Este algoritmo examina dinámicamente los
recursos asignados asegurando que nunca tendremos una condición de espera circular. El ESTADO de
asignación de recursos es definido por el número de recursos asignados y disponibles, y la demanda
máxima de los procesos.

Un estado será "seguro" si el sistema puede asignar recursos a cada proceso en algún orden sin entrar
en deadlock.

Dicho mas formalmente, un sistema esta en estado "seguro" si existe una secuencia segura. Una
secuencia de procesos p1, p2, ... , pn es segura para el estado de asignación actual si para cada pi, los
recursos necesitados por pi pueden ser satisfechos por la suma de los recursos disponibles en ese
momento mas los recursos asignados a todos los pj con j < i.

En esta situación, si el recurso necesitado por pi no esta disponible, puede esperar hasta que, pj haya
finalizado. Luego, pi obtiene todos sus recursos, completa su tarea y libera los mismos y termina. Cuando
pi termina, pi + 1 obtiene sus recursos, etc. Si no existe tal secuencia, entonces se dice que el estado del
sistema no es seguro.

Un estado seguro no es un estado en deadlock. Contrariamente, un estado de deadlock es un estado


inseguro. Sin embargo, no todos los estados inseguros son deadlocks. Un estado inseguro puede
terminar en deadlock.

En tanto esté en estado seguro, el S.O. puede evitar deadlock. En un estado inseguro, el S.O. no puede
prevenir que procesos pidiendo recursos puedan entrar en deadlock: la conducta de los procesos
controlan los estados inseguros.

Para ilustrar, consideremos un sistema con 12 unidades de cintas y 3 procesos:


p0, p, y p2. El proceso p0 requiere 10 unidades, el p1 puede necesitar hasta 4 y p2 hasta 9.
Supongamos que en el instante TO, p0 ya tiene asignadas 5 unidades, p1 2 unidades y p2 tiene 2. (Hay
3 unidades libres)

Necesidades máximas Actualmente asignadas


p0 10 5
p1 4 2
p2 9 2

En TO el sistema esta en estado seguro. La secuencia ( p1, p0, p2 ) satisface la condición de seguridad,
ya que p1 puede obtener las unidades que necesita, luego de liberadas el sistema tendrá 5 unidades
libres, entonces consigue las 5 adicionales, luego las libera y p2 consigue las 7 necesarias. Luego el
sistema tendrá las 12 cintas disponibles.

Observemos que es posible pasar de un estado seguro a otro inseguro.


Suponiendo que en T1, p2 pida una cinta adicional y se le asigne. En esta situación, el sistema ya no
esta en estado seguro, ya que solo a p1 se le podrá asignar los recursos remanentes. Cuando p1
termine, el sistema contara con solo 4 cintas libres y si p0 pide 5, debe esperar.
Adicionalmente, si p2 solicita las 6 cintas adicionales también tendrá que esperar, entrando en deadlock.
El error fue asignar a p2 la primer cinta adicional. Si hubiésemos hecho esperar a p2 hasta que
cualquiera de los otros procesos termine y libere las cintas, se puede evitar el deadlock.

Dado el concepto de estado seguro, se pueden definir algoritmos que eviten que el sistema entre en
deadlock. La idea simplemente es asegurar que el sistema siempre permanezca en un estado seguro.
Cuando un proceso requiera un recurso que esta disponible, el sistema debe decidir y si le asigna
inmediatamente el mismo o debe esperar. El pedido será satisfecho solo si deja al sistema en estado
seguro. Remarquemos que con este esquema de trabajo, un proceso que solicita un recurso que esta
actualmente disponible puede llegar a esperar, por lo tanto la utilización de recursos puede ser menor
que sin un modelo que evite deadlock.

Figura 8.6. Estados "seguro", "inseguro" y deadlock.

8.4.1. VARIAS INSTANCIAS PARA UN TIPO DE RECURSOS

El algoritmo descripto anteriormente es comúnmente conocido como algoritmo del banquero. El nombre
viene que el mismo puede usarse en un sistema de bancos para asegurar que el banco nunca asigne su
dinero disponible de forma tal que no pueda satisfacer las necesidades de todos sus clientes.

Cuando un proceso nuevo entra al sistema debe declarar el numero máximo de instancias de cada tipo
de recurso que puede necesitar. Este número no puede exceder el total de recursos del sistema. Cuando
un usuario requiere un conjunto de recursos, debe determinarse si la asignación de ellos dejará el
sistema en estado seguro. Si así sucede se le asignan los recursos; si no, el proceso debe esperar hasta
que se liberen recursos.

Deben mantenerse varias estructuras de datos para implementar el algoritmo del banquero. Allí se
codifica el estado de los recursos asignados por el sistema.

Sea n el numero de procesos en el sistema y m el número de tipos de recursos se necesita la siguiente


estructura de datos:

Disponibles: vector de longitud m indicando el número de recursos disponibles por cada tipo. Si
Disponible ( j ) = k, existen k instancias del tipo de recurso rj disponibles.

Máximos: matriz n x m que define la demanda máxima de cada proceso. Si Máximos ( i , j ) = k, entonces
el proceso pi puede pedir a lo sumo k instancias del tipo de recurso rj.

Asignados: matriz n x m que define el número de recursos de cada tipo actualmente asignados a cada
proceso. Si Asignados ( i , j ) = k, entonces el proceso pi tiene asignado k instancias del tipo de recurso rj.

Necesidades: matriz n x m que indica las necesidades remanentes de cada proceso.


Si Necesidades ( i , j ) = k, entonces el proceso pi puede necesitar k instancias más del tipo de recurso rj
para completar su tarea.

Estas estructuras de datos varían en tamaño y valores en el tiempo.


Para simplificar la presentación del algoritmo, convengamos en la notación siguiente: sean X e Y vectores
de longitud n. Decimos que X <= Y si y solo si

X ( i ) <= Y ( i )para todo i = 1, 2, ... , n.

Por ejemplo si X = (1,7,3,2) e Y = (0,3,2,1), entonces Y <= X.

Además Y < X si Y <= X e Y <> X.

Podemos tratar cada fila de las matrices Asignados y Necesidades como vectores y referirnos como
Asignados ( i ) y Necesidades ( i ) respectivamente.

Asignados ( i ) especifican los recursos corrientemente asignados al proceso pi.


Necesidades ( i ) especifican los recursos adicionales que el proceso pi puede aún requerir con el fin de
completar su tarea.

Algoritmo del Banquero

Pedidos ( i ) es el vector de requerimientos para el proceso pi

Si Pedidos ( i ,j ) = k, entonces el proceso pi desea k instancias del recurso de tipo rj. Cuando un pedido
de recursos es hecho por el proceso pi, se toman las siguientes acciones:

1.- Si Pedido ( i ) <= Necesidades ( i ) ir al paso 2. De lo contrario existe un error, ya que el proceso ha
excedido su numero de pedidos máximo.

2.- Si Pedido ( i ) <= Disponible, ir al paso 3. De lo contrario, los recursos no están disponibles, y el
proceso debe esperar.

3.- El sistema intenta asignar el pedido de recursos al proceso pi modificando el estado de la siguiente
manera:
Disponible := Disponible - Pedido ( i );
Asignados ( i ) := Asignados ( i )+ Pedido ( i );
Necesidades ( i ) := Necesidades ( i ) – Pedido ( i );

Si la asignación de recursos resultante es un estado seguro, se completa la transacción y se le asigna los


recursos a pi. Sin embargo, si el nuevo estado es inseguro, entonces pi debe esperar por Pedido ( i ) y se
restaura la asignación de recursos al estado anterior.
Algoritmo de Seguridad

El algoritmo para determinar si un sistema esta en estado seguro, puede describirse como:

1.- Sean Trabajo y Final vectores de longitud m y n respectivamente.


Inicializar Trabajo := Disponible y
Final ( i ) := falso para i = 1, 2, ..., n

2.- Encontrar un i tal que:


a) Final ( i ) = falso y
b) Necesidades ( i ) <= Trabajo
Si tal i no existe, ir a paso 4.
3.- Trabajo := Trabajo + Asignados ( i );
Final ( i ) := verdadero;
Ir a paso 2.
4.- Si Final (i) = verdadero para todo i, entonces el sistema está en estado seguro.

Ejemplo:

Consideremos un sistema con 5 procesos p0, p1, ..., p4 y 3 tipos de recursos A, B, C. El tipo de recurso
A tiene 10 instancias, el tipo B 5 instancias y el tipo C 7 instancias. Supongo que en tiempo TO, la
situación del sistema es:

Asignados Máximos Disponible


A B C A B C A B C
P0 0 1 0 7 5 3 3 3 2
P1 2 0 0 3 2 2
P2 3 0 2 9 0 2
P3 2 1 1 2 2 2
P4 0 0 2 4 3 3

El contenido de la matriz Necesidad se define como Máximo - Asignado y es:

Necesidad
A B C
P0 7 4 3
P1 1 2 2
P2 6 0 0
P3 0 1 1
P4 4 3 1

Afirmamos que el sistema esta actualmente en estado seguro. En la secuencia (p1, p3, p4, p2, p0)
satisface el criterio de seguridad.

Supongamos ahora que el proceso p1 pide una instancia adicional del tipo de recurso A y 2 instancias del
tipo de recurso C, así Pedido ( 1 ) = (1, 0, 2).

Para decidir si el pedido será satisfecho inmediatamente, primero debemos chequear que
Pedido ( 1 ) <= Disponible (o sea (1, 0, 2) <= (3, 3, 2), lo que es verdadero.
Luego suponemos que este pedido ha sido satisfecho y arribo al nuevo estado:

Asignados Necesidades Disponibles


A B C A B C A B C
P0 0 1 0 7 4 3 2 3 0
P1 3 0 2 0 2 0
P2 3 0 2 6 0 0
P3 2 1 1 0 1 1
P4 0 0 1 4 3 1

Ahora se debe determinar si este nuevo estado es seguro. Para saberlo se aplica el algoritmo de
seguridad y encontramos que la secuencia (p1, p3, p4, p0, p2) satisface el requerimiento de seguridad.
Por lo tanto, asignamos inmediatamente el pedido del proceso p1.

Debemos notar sin embargo, que en este estado un pedido de p4 (3,3,0), no puede ser satisfecho, ya
que los recursos no están disponibles. Otra situación, como un pedido de p0 ( 0, 2, 0 ) no puede ser
satisfecho, pues aunque los recursos están disponibles, el estado resultante no es seguro.

8.4.2. INSTANCIAS SIMPLES PARA CADA TIPO DE RECURSOS

Aunque el algoritmo del banquero es bastante general y anda para cualquier sistema de asignación de
recursos, puede requerir m x (n al cuadrado) operaciones.
Si tenemos un sistema con solo una instancia por cada tipo de recursos, puede definirse un algoritmo
más eficiente.
Este algoritmo usa una variante del gráfico de asignación de recursos visto en la sección 8.2.2. Además
de las flechas de pedido y asignación, tenemos un nuevo tipo llamada flecha de reserva (o declaración).
Una flecha ( pi , rj ) indica que el proceso p1 puede requerir un recurso rj, en algún momento futuro. Se
representa con líneas punteadas. Cuando el proceso efectivamente realiza el requerimiento, la flecha de
reserva se convierte en flecha de pedido de recurso.
Observemos que los recursos deben reclamarse a priori en el sistema. Es decir, antes de comenzar la
ejecución del proceso, ya deben aparecer todas las flechas de reserva en el gráfico.

Supongamos que el proceso pi pide un recurso rj. El pedido será satisfecho solo si la conversión de la
flecha de pedido (pi, rj) a una flecha de asignación (rj, pi) no resulta en la formación de un ciclo cerrado
en el gráfico.
Notemos que el chequeo de seguridad del sistema, se realiza usando un algoritmo de detección de
ciclos, que requiere (n al cuadrado) operaciones, donde n es el número de procesos en el sistema.
Si no se forma un ciclo, entonces la asignación del recurso dejará el sistema en estado seguro; si se
forma un ciclo, el sistema quedará en estado inseguro, por lo tanto el proceso pi tendrá que esperar para
que el pedido sea satisfecho.

Ejemplos: Figura 8.7. Supongo que p2 pide r2. Aunque r2 esta actualmente libre, no podemos asignar el
recurso, ya que esta acción crea un ciclo. (Figura 8.8.)
Un ciclo indica que el sistema queda inseguro: si p1 luego pide r2, ocurre un deadlock.

Figura 8.7. Gráfico para evitar deadlock

Figura 8.8. Estado inseguro.


8.5. DETECCION DE DEADLOCK

Si el sistema no usa algún protocolo que asegure que un deadlock nunca va a ocurrir, entonces debe
implementarse un método de detección y recuperación.
Un algoritmo que examina el estado del sistema se invoca periódicamente para determinar si ha ocurrido
un deadlock. Si existe, el sistema debe intentar recuperarse, por lo que debe tomar las siguientes
acciones:

a.- Mantener información de la asignación actual de recursos a los procesos, tanto como los pedidos de
asignación de recursos en espera.
b.- Proveer un algoritmo que utilice esta información para determinar cuando el sistema ha entrado en
estado de deadlock.

En las secciones siguientes veremos los puntos a y b en lo que respecta a sistemas con varias instancias
de cada tipo de recursos y también a sistemas con una sola instancia por tipo de recursos. Aclaremos, sin
embargo, que el método de detección y recuperación requiere una sobrecarga de trabajo al sistema que
incluye no solo el costo de ejecución de mantener la información necesaria y ejecutar el algoritmo de
detección, sino también las potenciales perdidas de información que implican la recuperación del sistema
de un deadlock.

8.5.1. VARIAS INSTANCIAS POR TIPO DE RECURSOS

El algoritmo de detección emplea varias estructuras de datos muy similares a las usadas en el algoritmo
del banquero (Sección 8.4.1.):

• Disponibles: vector de longitud m que indica el número de recursos disponibles de cada tipo.
• Asignados: matriz. de n x m, que define el número de recursos de cada tipo actualmente
asignados a cada proceso.
• Pedidos matriz de n x m que indica los pedidos actuales de cada proceso. Si Pedido ( i , j ) = k,
significa que el proceso pi esta solicitando k más instancias del recurso tipo rj.

La relación " < " entre 2 vectores se define igual que en la Sección 8.4. Para simplificar la notación,
trataremos las filas de las matrices Asignados ( i ) y Pedidos ( i ) como vectores. El algoritmo de detección
descripto lo idearon Shoshani y Coffman (1970), y simplemente investiga cada secuencia de asignación
posible para los procesos que restan finalizar su ejecución. Comparar este algoritmo con el del Banquero
de la Sección 8.4.1.

1.- Sea Trabajo y Final vectores de longitud m y n, respectivamente.


Inicializar Trabajo := Disponible.
Para i = 1, 2, ... , n si Asignados ( i ) <> 0, luego Final ( i ) := falso; de lo contrario
Final ( i ) := verdadero.
2.- Encontrar un índice i, tal que:
a.- Final ( i ) falso y
b.- Pedidos ( i ) <= Trabajo.
Si tal i no existe ir a paso 4.
3.- Trabajo := Trabajo + Asignación ( i )
Final ( i ) = verdadero.
Ir a paso 2.
4.- Si Final ( i ) = falso, para algún i, 1 <= i <= n, entonces el sistema esta en deadlock. Si Final ( i ) =
falso, entonces el proceso pi esta en deadlock.

Puede surgir la duda de porque se reasignan recursos del proceso pi. Cuando se determina que
Pedido ( i ) <= Trabajo. Sabemos que pi actualmente no está envuelto en deadlock. Por ende, tomamos
una actitud optimista y suponemos que pi no requerirá más recursos para completar su tarea, y luego
devolverá todos sus recursos asignados cuando termine. Si esto no es así, un deadlock puede ocurrir
más tarde, el que será detectado luego, al invocarse el algoritmo de detección la próxima vez.
Ejemplo: Consideremos un sistema con 5 procesos ( p0, p1, p2, p3, p4 ) y 3 tipos de recursos ( A, B, C ).
A = 7 instancias; B = 2 instancias y C = 6 instancias. Supongo que en tiempo T0, tenemos el siguiente
estado de asignación de recursos:

Asignados Pedidos Disponible


A B C A B C A B C
p0 0 1 0 0 0 0 0 0 1
p1 2 0 0 2 0 2
p2 3 0 2 0 0 0
p3 2 1 1 1 0 0
p4 0 0 2 0 0 2

Afirmamos que el Sistema no esta en estado de deadlock. Efectivamente, si ejecutamos nuestro


algoritmo, encontramos que la secuencia ( p0, p2, p3, p1, p4) resultara en FINAL (i) = verdadero para
todo i.

Supongamos ahora que el proceso p2 hace un pedido adicional para una instancia del tipo C. La
matriz Pedidos se modifica así:

Pedidos
A B C
p0 0 0 0
p1 2 0 2
p2 0 0 1
p3 1 0 0
p4 0 0 2

Afirmamos que el sistema ahora esta en deadlock. Aunque podamos recuperar los recursos de p0, el
numero de recursos disponibles no es suficiente para los pedidos de los demás procesos. Por ende,
existe un deadlock, consistente con la secuencia p1, p2, p3 y p4.

8.5.2. UNICA INSTANCIA PARA CADA TIPO DE RECURSOS

Igual que el algoritmo de evitar deadlocks, este de detección necesita m x (n al cuadrado) operaciones. Si
todos los recursos tienen una sola instancia, puedo definir un algoritmo mas veloz. Nuevamente, usamos
una variante del grafico de asignación de recursos, llamado gráfico en espera. Se obtiene eliminando
todos los nodos de tipo de recursos del grafico de asignación de recursos y uniendo las flechas
apropiadas.

Una flecha desde pi a pj en un grafico en espera, implica que un proceso pi está esperando que un
proceso pj libere un recurso que necesita. Una flecha (pi , pj) existe si y solo si el grafico de asignación de
recursos correspondiente contiene 2 flechas ( pi, rq ) y ( rq , pi ) para algún recurso rq. Por ejemplo, en la
Fig. 8.9. y 8.10 se muestran ambos tipos de gráficos.
Figura 8.9. Gráfico de asignación de recursos

Figura 8.10. Gráfico en espera correspondiente

Igual que antes, existe deadlock en el sistema si y solo si el gráfico en espera contiene un ciclo cerrado.
Para detectar un deadlock, el sistema debe mantener el gráfico en espera y periódicamente invocar un
algoritmo de búsqueda por un ciclo en el grafo. Un algoritmo de este tipo necesita (n al cuadrado)
operaciones, donde n es el número de vértices del grafo. Aunque esta sobrecarga de trabajo para el
sistema es menor que la de un algoritmo general de deadlock, el costo de detección de ciclos sigue
siendo alto.

8.5.3. USO DE LOS ALGORITMOS DE DETECCIÓN

Cuando se debe invocar a un algoritmo de detección de deadlocks?. La respuesta depende de dos


factores:

• Cuan a menudo se cree que ocurrirá un deadlock?


• Cuantos procesos serán afectados por un deadlock, cuando ocurra el mismo?

Si los deadlocks ocurrirán muy a menudo, entonces el algoritmo de detección deberá pasarse más
frecuentemente. Los recursos asignados a procesos en deadlocks permanecerán ociosos hasta que se
rompa esta situación de deadlock. Además el numero de procesos involucrados en un ciclo en deadlock
puede aumentar.

Un deadlock puede aparecer solo si algún proceso hace un pedido de un recurso que no puede ser
satisfecho inmediatamente. Puede ocurrir, que este pedido sea el que complete una cadena de procesos
en espera. Como caso extremo podría invocar al algoritmo de detección cada vez que un pedido de
recurso no puede ser satisfecho inmediatamente. En este caso podemos identificar no solo los procesos
que están en deadlock, sino también el proceso en particular que ha provocado el mismo. (en realidad,
cada proceso es un eslabón del ciclo del gráfico de recursos, y todos causan el deadlock).

Por supuesto, que esta solución de invocar el algoritmo de detección por cada pedido provocara una
enorme sobrecarga al sistema. Un estrategia menos costosa es invocar al algoritmo menos
frecuentemente, por ejemplo una vez cada hora, o cuando la utilización de CPU bajo de un 40% (ya que
un deadlock baja el rendimiento de un equipo, causando que la utilización de CPU baje). Si el algoritmo
de detección se invoca en puntos arbitrarios de tiempo, puede ser que existan varios ciclos en el grafo,
entonces no será posible decir cual proceso fue el causante del deadlock.
8.6. RECUPERACION DE UN DEADLOCK

Cuando un algoritmo de detección encuentra un deadlock, el sistema debe recuperarse de esta


situación, rompiendo el mismo. Existen 2 opciones para esto: una simplemente es terminar uno o más
procesos, para romper la espera circular y otra opción es sacar en forma forzada algunos recursos a uno
o más procesos que intervienen en el deadlock.

8.6.1. TERMINACION DE PROCESOS

Para la eliminación de un deadlock terminando un proceso, pueden haber 2 métodos. En ambos el


sistema retoma todos los recursos asignados al proceso terminado.

• Matar todos los procesos en deadlock: Esto evidentemente romperá el ciclo del deadlock, pero a
un gran costo, ya que estos procesos pueden haber realizado por un largo tiempo muchas
operaciones, las que deben reiniciarse luego.
• Matar un proceso por vez hasta eliminar el ciclo de deadlock: este método produce una
considerable sobrecarga al sistema, ya que luego de matar un proceso, debe invocarse a un
algoritmo de detección de deadlock para determinar si otros procesos siguen en deadlock.

Observemos que terminar un proceso puede no ser fácil. Si el mismo se encontraba actualizando un
archivo en disco y lo abortamos, dejaremos el archivo en un estado incorrecto. Si uso el método de
terminación parcial, dado el conjunto de procesos en deadlock, debo determinar cual proceso o procesos
debo terminar para tratar de romper el deadlock. Esto, implica una política de decisión, similar a los
problemas de planificación de CPU. La pregunta pasa por una cuestión de "economía": debo terminar
los procesos que me produzcan el mínimo costo. Desafortunadamente, el termino "mínimo costo" no es
muy preciso, ya que intervienen muchos factores para llegar a elegir un proceso a terminar, por ejemplo:

1.- La prioridad del proceso.


2.- Tiempo de iniciado el proceso y tiempo de computación restante hasta completar su tarea.
3.- Cuantos y que tipo de recursos ha usado el proceso (por ejemplo, es fácil de provocar una liberación
forzada de ese recurso ??)
4.- Cuantos más recursos el proceso necesita para su tarea.
5.- Cuantos procesos están involucrados en la terminación.

8.6.2. LIBERACION FORZADA DE RECURSOS (PRE-EMPTION)

Para eliminar deadlocks usando la liberación forzada de recursos, sucesivamente liberamos algunos
recursos de procesos y los damos a otros proceso hasta romper el ciclo de deadlock.

Si uso este método, debo tener en cuenta 3 aspectos:

* Selección de una víctima: Que recursos y que procesos debemos liberar en forma forzada? Como en la
terminación de procesos, debemos determinar un orden para minimizar costos.

Volviendo al ejemplo del cruce del río, supongo que hay 1.000 piedras y considero una situación de
deadlock entre 2 personas P y Q. Si considero que P tiene una mayor prioridad que Q (por ejemplo, P
puede ser un policía), entonces Q tendrá que retroceder sin ninguna alternativa. Si P necesita solo 2
piedras para terminar el cruce (es decir ha pasado ya por 998 piedras), es razonable hacer retroceder a
Q. Si el deadlock se produce en la mitad del río y no hay nadie detrás de Q pero si hay 10 personas tras
P, es razonable hacer retroceder a Q, ya que de otro modo 11 personas lo tendrán que hacer.
* Rollback: si libero un recurso de un proceso, que hago con ese proceso ? Obviamente, el mismo no
puede seguir con su ejecución normal ya que le falta un recurso. Debemos retroceder a un estado seguro
del mismo y reiniciarlo desde ahí. Pero, que constituye un estado seguro y cuán fácil es su determinación
?. Lo mas fácil es un rollback total: abortar el proceso y luego, recomenzarlo. Pero es mas efectivo
retroceder solo lo necesario como para romper el deadlock. Sin embargo, este método requiere que el
sistema guarde más información acerca del estado de todos los procesos en ejecución. Volvamos al
ejemplo del cruce del río. El rollback total es equivalente que la persona retorne totalmente a donde
comienzo el viaje (por ejemplo si una persona de Resistencia al cruzar un río en Buenos Aires,
obliguemos a retornar a Resistencia). Esta solución no es efectiva desde el punto de vista de costos. Es
mas natural romper el ciclo de un deadlock haciendo retroceder a la persona solo hasta una orilla. Otra
solución más efectiva es poner algunas piedras al costado, para que una persona se haga a un lado para
dejar pasar la otra. En un sistema de computación puede realizarse un checkpoint, es decir grabar el
estado de un proceso para permitir un rollback.

* Inanición: Como aseguramos que no ocurrirá inanición ? Es decir, como garantizamos que recursos no
serán siempre obligados a ser liberados en forma forzada de un mismo proceso ?
En un sistema, donde la víctima se selecciona sobre factores eminentemente de costo, puede suceder
que siempre se elija al mismo proceso como víctima. Como resultado, este proceso nunca termina su
ejecución. Esta situación es conocida como inanición, y se debe considerar en cualquier sistema en la
practica.
Se debe asegurar que un proceso pueda ser victima solo un numero finito y muy pequeño de veces. La
solución mas común es agregar el numero de rollbacks en el factor de costo.

8.7. SOLUCION COMBINADA PARA EL MANEJO DE DEADLOCKS

Se ha argumentado que ninguna de las soluciones básicas para el manejo deadlocks (prevención, evitar
el deadlock y detección) por si sola es apropiada para todo el espectro de los problemas de asignación
de recursos que se encuentran en un S.O. Howard (1973) ha sugerido que las técnicas pueden
combinarse, permitiendo el uso de la optima para cada clase de recurso del sistema. El método
propuesto se basa en la idea de que los recursos pueden particionarse en clases que son ordenadas en
forma jerárquica. A las clases se les aplica una técnica de ordenamiento de recursos. Luego, cada clase
será manejada con la técnica más apropiada para el manejo de los deadlocks.

Es fácil demostrar que un sistema que emplea esta estrategia nunca estará sujeto a deadlocks. En
efecto, un deadlock -de producirse- nunca involucra a más de una clase de recursos, ya que se usa la
técnica de ordenamiento. (Sección 8.3.4). Dentro de cada clase, se usa la solución básica mas
adecuada.

Ejemplo: Consideremos un sistema con 4 clases de recursos:

* Recursos internos: recursos usados por el sistema, tales como bloques de control de procesos.
* Memoria principal: memoria usada por los trabajos de usuarios.
* Recursos para trabajos: dispositivos posibles de ser asignados (tales como unidades de cinta
magnética) y archivos.
* Espacio swappeable: espacio para cada trabajo de usuario en la memoria soporte.

Una solución ideal mixta para el manejo de deadlocks en este sistemas, ordena las clases y usa métodos
de la siguiente manera:

* Recursos internos: Puede usarse, a través de ordenamiento de recursos, la prevención de deadlocks,


ya que la elección en tiempo de ejecución entre pedidos pendientes no es necesaria.
* Memoria principal: Puede usarse prevención a través de liberación forzada, ya que un trabajo siempre
puede ser swappeado.
* Recursos para trabajos: Acá puede usarse la técnica de evitar deadlocks, ya que la, información de
requerimientos de recursos puede obtenerse de las tarjetas de control de trabajos.
* Espacio swappeable: puede usarse preasignación, ya que la necesidad máxima de almacenamiento
usualmente es conocida.
PROBLEMAS DEADLOCK

Dados las siguientes matrices de máximos, asignados y vector disponible: calcular la matriz de
necesidades. Con el dato de Pedido correspondiente a un proceso dado, aplicar algoritmo del banquero y
algoritmo de seguridad a fin de determinar si el mismo puede ser satisfecho o debe esperar.

1) Asignados Máximos Disponible


A B C A B C A B C
P0 0 1 0 7 5 3 3 3 2
P1 2 0 0 3 2 2
P2 3 0 2 9 0 2
P3 2 1 1 2 2 2
P4 0 0 2 4 3 3

Para Pedido ( 1 ) = ( 1, 0, 2 ).

Para Pedido ( 4) = ( 3, 3, 0 )

Para Pedido ( 0 ) = ( 0, 2, 0 )

2) Asignados Máximos Disponible


A B C D A B C D A B C D
P0 0 0 1 2 0 0 1 2 1 5 2 0
P1 1 0 0 0 1 7 5 0
P2 1 3 5 4 2 3 5 6
P3 0 6 3 2 0 6 5 2
P4 0 0 1 4 0 6 5 6 Para Pedido ( 1 ) = ( 0, 4, 2, 0 )

3) Asignados Máximos Disponible


A B C D A B C D A B C D
P0 2 1 1 3 4 5 8 3 3 2 0 1
P1 3 1 0 3 3 4 1 4
P2 0 2 2 0 1 3 2 0
P3 2 4 2 2 8 7 3 3
P4 0 1 2 1 0 2 6 1 Para Pedido ( 2 ) = ( 1, 1, 0, 0 )

4) Asignados Máximos Disponible


A B C D A B C D A B C D
P0 1 3 0 2 2 3 6 3 2 3 2 2
P1 2 1 1 0 3 5 2 4
P2 0 0 1 2 1 2 3 2
P3 2 0 1 0 3 3 5 2
P4 0 1 1 0 1 1 2 2 Para Pedido ( 3 ) = ( 1, 1, 0, 2 )

S-ar putea să vă placă și