Buscar este blog

sábado, 15 de enero de 2011

2.12 concurrencia e Interbloqueo deadlock

2.12 concurrencia e Interbloqueo deadlock

 Deadlock: Simple y Avanzado
Hay un fallo de codificación donde un pedazo de código intenta obtener un spinlock dos veces: él esperará siempre, esperando a que el bloqueo sea liberado (spinlocks, rwlocks y semáforos no son recursivos en Linux). Esto es trivial de diagnosticar: no es un tipo de problema de estar-cinco-noches-despierto-hablando-con-los-suaves-conejitos-del-código.
Para un caso ligeramente más complejo, imagínate que tienes una región compartida por un bottom half y un contexto de usuario. Si usas una llamada spin_lock() para protegerla, es posible que el contexto de usuario sea interrumpido por el bottom half mientras mantiene el bloqueo, y el bottom half entonces esperará para siempre para obtener el mismo bloqueo.
Ambas son llamadas deadlock (bloqueo muerto), y como se mostró antes, puede ocurrir con una CPU simple (aunque no en compilaciones para UP, ya que los spinlocks se desvanecen en la compilación del núcleo con CONFIG_SMP=n. Aún tendrás corrupción de datos en el segundo ejemplo).
Este bloqueo completo es fácil de diagnosticar: en equipos SMP el cronómetro guardián o compilado con DEBUG_SPINLOCKS establecido (include/Linux/spinlock.h) nos mostrará esto inmediatamente cuando suceda.
Un problema más complejo es el también llamado `abrazo mortal', involucrando a dos o más bloqueos. Digamos que tienes una tabla hash: cada entrada en la tabla es un spinlock, y una cadena de objetos ordenados. Dentro de un manejador softirq, algunas veces quieres alterar un objeto de un lugar de la tabla hash a otro: coges el spinlock de la vieja cadena hash y el spinlock de la nueva cadena hash, y borras el objeto de la vieja y lo insertas en la nueva.
Los mejores bloqueos están encapsulados; nunca estarán expuestos en las cabeceras, y nunca se mantendrán a través de llamadas a funciones no triviales fuera del mismo archivo. Puedes leer a través de este código y ver que nunca hará deadlock, porque nunca intenta tener otro bloqueo mientras tiene el uso. La gente usando tu código no necesita saber nunca que estás usando un bloqueo.
Un problema clásico aquí es cuando suministras retrollamadas o trampas: si las llamas con el bloqueo mantenido, arriesgas un deadlock simple, o un abrazo mortal (¿quién sabe lo que hará la llamada?). Recuerda, los otros programadores andan detrás de ti, por lo tanto no hagas esto.

No hay comentarios:

Publicar un comentario