Ir al contenido

Clase de teoría sem. 11 · Deadlock (lo que añade al libro)

🎯 Al terminar podrás

  1. Distinguir starvation, livelock y deadlock con un ejemplo de cada uno.
  2. Encontrar el deadlock en código real (productor–consumidor con los P() invertidos, transferencias con dos locks) y corregirlo.
  3. Decidir con el grafo de asignación si un ciclo es deadlock según las instancias, y construir el grafo de espera.
  4. Ejecutar a mano el banquero (Need, seguridad y peticiones) y el algoritmo de detección.

Antes necesitas: Coffman y los tres enfoques

  • Detective escribe tu hipótesis del bug antes de abrir el diagnóstico
  • Laboratorio sube la escalera: resuelto → completa → solo → variante
  • Examen cronométrate y no abras la solución hasta terminar
Qué pasaEjemplo de la clase
StarvationUn hilo espera indefinidamente, aunque el sistema sigue avanzandohilos de baja prioridad que nunca corren porque siempre hay otros de alta
LivelockUn caso especial de starvation: los estados de los procesos cambian todo el tiempo, pero ninguno progresados hilos que se ceden el paso eternamente (como el trylock + reintentar del lab 11)
DeadlockEspera circular por recursos: nadie se mueveel hilo A tiene Res 1 y espera Res 2; el hilo B tiene Res 2 y espera Res 1

Relación clave: todo deadlock es starvation, pero no al revés. En un deadlock los procesos involucrados esperan para siempre, pero puede haber starvation sin ningún ciclo.

  • Los recursos son de tipos R1 … Rm, y cada tipo Ri tiene Wi instancias.
  • Cada proceso usa un recurso en tres pasos: 1) pedir (request), 2) usar (use), 3) liberar (release).
ClasificaciónQué significaEjemplos
Expropiable (preemptible)el SO puede quitarlo sin problemaCPU
No expropiableno se le puede quitar al hiloespacio en disco, impresora, derecho a entrar a una sección crítica
Compartible vs exclusivo¿varios lo pueden usar a la vez?archivo de solo lectura (compartible) vs impresora (exclusivo)
Reutilizable vs consumiblecomo en el libromemoria y semáforos vs mensajes y señales

Expropiar (preemption) es interrumpir temporalmente lo que hace una tarea, con la intención de reanudarla después.

Ejemplo 1 · Productor–consumidor con los P() invertidos

Sección titulada «Ejemplo 1 · Productor–consumidor con los P() invertidos»

La versión correcta pide primero el semáforo de conteo y después el mutex:

Producer(item) { Consumer() {
emptySlots.P(); fullSlots.P();
mutex.P(); mutex.P();
Enqueue(item); item = Dequeue();
mutex.V(); mutex.V();
fullSlots.V(); emptySlots.V();
} return item; }

La clase cambia el orden solo en el productor: primero mutex.P() y después emptySlots.P().

Dos hilos que toman dos mutex en orden opuesto (recurso reutilizable):

void *do_work_one(void *param) { void *do_work_two(void *param) {
pthread_mutex_lock(&first_mutex); pthread_mutex_lock(&second_mutex);
pthread_mutex_lock(&second_mutex); pthread_mutex_lock(&first_mutex);
... ...
} }

Si el hilo 1 toma first_mutex y el hilo 2 toma second_mutex, cada uno espera el del otro.

Transferencias bancarias (lock ordering deadlock): aquí el orden lo deciden los argumentos.

void transaction(Account from, Account to, double amount) {
lock1 = get_lock(from);
lock2 = get_lock(to);
acquire(lock1);
acquire(lock2);
withdraw(from, amount);
deposit(to, amount);
release(lock2);
release(lock1);
}

La transacción 1 hace A → B (25)yla2haceB→A(25) y la 2 hace B → A (50), las dos al mismo tiempo.

  • Exclusión mutua: no hace falta para recursos compartibles (archivos de solo lectura); sí para los no compartibles.
  • Hold and wait, dos opciones:
    1. pedir y recibir todos los recursos antes de empezar;
    2. pedir recursos solo cuando no se tiene ninguno.
    • Desventajas: baja utilización de los recursos y posible starvation.
  • No expropiación: si un proceso que tiene recursos pide uno que no se le puede dar ya, libera todo lo que tiene. Lo liberado pasa a su lista de espera y el proceso se reinicia solo cuando puede recuperar lo viejo y lo nuevo.
  • Espera circular: un orden total de los tipos de recurso, pidiéndolos en orden creciente.

Grafo de asignación y cuándo un ciclo es deadlock

Sección titulada «Grafo de asignación y cuándo un ciclo es deadlock»
  • Arista de petición: Pi → Rj.
  • Arista de asignación: Rj → Pi.
  • Arista de reclamo (claim): Pi ⇢ Rj, punteada. Indica que Pi podría pedir Rj en el futuro; se usa en la evitación.
El grafo…Conclusión
No tiene ciclosno hay deadlock
Tiene un ciclo y una instancia por tipohay deadlock
Tiene un ciclo y varias instancias por tipoposibilidad de deadlock: hay que analizar

El ejercicio de la clase («¿este grafo representa un deadlock?»): no lo hay si se puede ir liberando.

  1. T3 termina y libera R4 y R2.
  2. Con eso, T2 termina y libera R1, R2 y R3.
  3. Luego T1 termina.

Si existe un orden así, no hay deadlock aunque haya un ciclo. En los dos grafos siguientes de la clase, uno sí tiene deadlock (nadie puede terminar) y el otro no, porque un hilo fuera del ciclo (T2 o T4) libera una instancia.

InstanciasEvitaciónDetección
Una por tipoanalizar el grafo de asignacióngrafo de espera (wait-for): los nodos son solo procesos, con Pi → Pj si Pi espera a Pj. Hay deadlock si y solo si hay un ciclo. Buscarlo cuesta O(n²)
Varias por tipobanqueroalgoritmo con Available, Allocation y Request, de costo O(m × n²)

El grafo de espera se obtiene del grafo de asignación eliminando los nodos de recurso y uniendo directamente al que espera con el que tiene el recurso.

El banquero en notación Silberschatz (como en la clase)

Sección titulada «El banquero en notación Silberschatz (como en la clase)»
  • Need = Max − Allocation.
  • Petición de Pi:
    1. si Request ≤ Need, ir al paso 2; si no, error (superó su máximo);
    2. si Request ≤ Available, ir al paso 3; si no, esperar;
    3. simular: Available −= Request, Allocation += Request, Need −= Request. Si el estado es seguro se asigna; si no, se restaura y Pi espera.
  • Seguridad:
    1. Work = Available y Finish = false;
    2. buscar un i con Finish[i] = false y Need_i ≤ Work, hacer Work += Allocation_i y Finish[i] = true, y repetir;
    3. si todos tienen Finish = true, el estado es seguro.
  • Estado seguro (definición de la clase): existe una secuencia ⟨P1 … Pn⟩ con todos los procesos en la que lo que Pi aún puede pedir se cubre con lo disponible más lo que tienen todos los Pj con j < i.
  • Seguro ⇒ no hay deadlock. Inseguro ⇒ posibilidad de deadlock. La evitación garantiza no entrar nunca en un estado inseguro.

Ejemplo clásico de Silberschatz: 5 procesos y recursos A = 10, B = 5, C = 7.

Allocation (A B C)Max (A B C)Need = Max − Alloc
P00 1 07 5 37 4 3
P12 0 03 2 21 2 2
P23 0 29 0 26 0 0
P32 1 12 2 20 1 1
P40 0 24 3 34 3 1

Available = (10, 5, 7) − la suma de Allocation = (3, 3, 2).

Peldaño 1 · Resueltolee cada paso y su porqué

Resuelto: ¿el estado es seguro?

Paso¿Quién?Need ≤ WorkWork después (+ Allocation)
0——3 3 2
1P11 2 2 ≤ 3 3 2 ✓5 3 2
2P30 1 1 ≤ 5 3 2 ✓7 4 3
3P07 4 3 ≤ 7 4 3 ✓7 5 3
4P26 0 0 ≤ 7 5 3 ✓10 5 5
5P44 3 1 ≤ 10 5 5 ✓10 5 7

Todos terminan: el estado es seguro, con la secuencia ⟨P1, P3, P0, P2, P4⟩. Hay otras válidas, como ⟨P1, P3, P4, P2, P0⟩, la del libro de Silberschatz. Al terminar, Work debe volver al total (10, 5, 7): es una buena forma de comprobar las sumas.

Peldaño 2 · Complétalofaltan pasos clave: llénalos tú

Complétalo: P1 pide (1, 0, 2)

Los pasos 1 y 2 de la petición ya están: Request (1 0 2) ≤ Need de P1 (1 2 2) ✓, y Request ≤ Available (3 3 2) ✓. Completa el paso 3: simula la asignación (nuevo Available, nuevo Allocation y nuevo Need de P1) y corre el algoritmo de seguridad. ¿Se concede?

Comparar (verificado con un script)
  • Available = 3 3 2 − 1 0 2 = 2 3 0. Allocation de P1 = 3 0 2. Need de P1 = 0 2 0.
  • Seguridad: P1 (0 2 0 ≤ 2 3 0) → Work 5 3 2 → P3 → 7 4 3 → P0 → 7 5 3 → P2 → 10 5 5 → P4 → 10 5 7.
  • Es seguro: se concede.

Peldaño 3 · Solosin ayuda; luego compara

Solo: después de conceder lo anterior, llegan dos peticiones: P4 pide (3, 3, 0) y P0 pide (0, 2, 0)

Comparar (verificado con un script)
  • P4 (3 3 0): es ≤ su Need (4 3 1), pero no es ≤ Available (2 3 0), porque falta A. P4 espera, sin simular nada.
  • P0 (0 2 0): es ≤ su Need (7 4 3) y ≤ Available. Se simula: Available queda en 2 1 0. Ahora nadie cumple Need ≤ Work: P1 necesita 2 de B, P3 necesita 1 de C y los demás necesitan más A. El estado es inseguro, así que se deniega, se restaura el estado y P0 espera.

Peldaño 4 · Variantecambia una condición: ¿sigue valiendo lo anterior?

Variante: la misma petición de P0 (0, 2, 0), pero en el estado original (antes de conceder lo de P1)

Comparar

Ahora sí se concede. Available queda en 3 1 2 y existe la secuencia segura ⟨P3, P1, P0, P2, P4⟩ (verificada con un script). Lección: el banquero no juzga la petición en sí, sino el estado al que lleva. La misma petición puede ser segura o insegura según lo que ya se haya asignado. Que se deniegue no significa que habría habido deadlock: el banquero es conservador.

Hay 5 procesos y 3 recursos: A = 7, B = 2 y C = 6. Available = (0, 0, 0).

Allocation (A B C)Request (A B C)
P00 1 00 0 0
P12 0 02 0 2
P23 0 30 0 0
P32 1 11 0 0
P40 0 20 0 2
¿Hay deadlock? ¿Y si P2 pide una C más?

Estado inicial: no hay deadlock. La clase da la secuencia ⟨P0, P2, P3, P1, P4⟩, con Finish = true para todos. Por ejemplo, P0 no pide nada y libera (0, 1, 0); P2 tampoco pide y libera (3, 0, 3), y así sucesivamente. El script encontró otra secuencia válida, ⟨P0, P2, P1, P3, P4⟩: puede haber varias.

P2 pide una C más (su fila de Request pasa a 0 0 1):

  • Solo P0 puede terminar (no pide nada), y entonces Work = (0, 1, 0).
  • Con eso nadie más puede: P1 pide 2 A, P2 pide 1 C, P3 pide 1 A y P4 pide 2 C.
  • Hay deadlock entre P1, P2, P3 y P4.

Las dos respuestas están verificadas con un script del algoritmo de detección.

Ojo con el paso 1: a los procesos con Allocation = 0 se les pone Finish = true desde el inicio (en Stallings: «marcar los que tienen la fila en ceros»).

¿Cada cuánto correrlo? Si se invoca de forma arbitraria puede haber muchos ciclos en el grafo, y no se sabría cuál proceso «causó» el deadlock.

Terminando procesos: abortar todos los que están en deadlock, o uno a la vez hasta romper el ciclo. Para elegir a quién:

  1. la prioridad del proceso;
  2. cuánto ha computado y cuánto le falta;
  3. los recursos que ya usó;
  4. los recursos que necesita para terminar;
  5. cuántos procesos habrá que terminar;
  6. si es interactivo o batch.

Expropiando recursos:

  • Elegir víctima minimizando el costo.
  • Rollback: volver a un estado seguro y reiniciar desde ahí.
  • Starvation: puede salir siempre la misma víctima. La solución es incluir el número de rollbacks en el costo.
  • No hay una estrategia que sirva para todo tipo de deadlock.
  • Otra solución es ignorarlo (la «del avestruz»). La usan la mayoría de los SO, como UNIX y Linux, excepto en las funciones del kernel.
  • Dentro del kernel, Linux usa lockdep (Lock Dependency Validator, en kernel/locking/lockdep.c):
    • detecta de forma dinámica y proactiva los deadlocks de spinlocks y mutex;
    • verifica que los locks se tomen siempre en un orden consistente en todo el código del kernel (es la prevención de la espera circular, comprobada en ejecución);
    • Linux propone además un mecanismo nuevo: DEPT (Dependency Tracker).

Clase de teoría sem. 11

0/12 correctas · 0 respondidas
1. ¿Cuál afirmación es correcta?
2. En el productor–consumidor, el productor hace mutex.P() antes que emptySlots.P(). Con el buffer lleno…
3. Transferencias A→B y B→A con dos locks pueden tener deadlock. La solución estándar es…
4. El derecho a entrar a una sección crítica es un recurso…
5. Un grafo de asignación con un ciclo y una instancia por tipo…
6. El grafo de espera (wait-for) se usa cuando…
7. Costo del algoritmo de detección con varias instancias:
8. En el ejemplo de 5 procesos, P2 pide una C más. Resultado:
9. Al expropiar recursos para recuperarse, ¿cómo se evita que siempre caiga la misma víctima?
10. ¿Qué hace lockdep en Linux?
11. La mayoría de los SO (UNIX, Linux) ante el deadlock de procesos de usuario…
12. Prevenir hold and wait pidiendo todo antes de empezar tiene como desventajas…

📈 ¿Qué tan bien lo dominas?

Elige pensando en lo que hiciste, no en lo que leíste. Para marcar 3 tienes que haber resuelto un ejercicio nuevo sin pistas y haberlo justificado. Si solo lo leíste y sientes que «ya entendí», todavía es un 1.

Fuente ·sem_11/Sem11_11-OST-Deadlock.pdf (clase de teoría 11) · Stallings 9e, cap. 6 · Ejemplos verificados con scripts propios: recorrido de todos los estados del productor–consumidor y algoritmo de detección · La corrección de la transferencia es una solución propia