Interbloqueos

Un interbloqueo se produce cuando dos o más tareas se bloquean entre sí permanentemente teniendo cada tarea un bloqueo en un recurso que las otras tareas intentan bloquear. Por ejemplo:

  • La transacción A tiene un bloqueo compartido de la fila 1.

  • La transacción B tiene un bloqueo compartido de la fila 2.

  • La transacción A ahora solicita un bloqueo exclusivo de la fila 2 y se bloquea hasta que la transacción B finalice y libere el bloqueo compartido que tiene de la fila 2.

  • La transacción B ahora solicita un bloqueo exclusivo de la fila 1 y se bloquea hasta que la transacción A finalice y libere el bloqueo compartido que tiene de la fila 1.

La transacción A no puede completarse hasta que se complete la transacción B, pero la transacción B está bloqueada por la transacción A. Esta condición también se llama dependencia cíclica: la transacción A tiene una dependencia de la transacción B y la transacción B cierra el círculo teniendo una dependencia de la transacción A.

Ambas transacciones con un interbloqueo esperarán para siempre, a no ser que un proceso externo rompa el interbloqueo. La supervisión de interbloqueos del SQL Server Database Engine (Motor de base de datos de SQL Server) de Microsoft comprueba periódicamente si hay tareas con un interbloqueo. Si el monitor detecta una dependencia cíclica, selecciona una de las tareas como el sujeto y finaliza su transacción con un error. Esto permite a la otra tarea completar su transacción. La aplicación con la transacción que terminó con un error puede reintentar la transacción, que suele completarse después de que la otra transacción interbloqueada haya finalizado.

El uso de ciertas convenciones de código en las aplicaciones reduce la probabilidad de que las aplicaciones causen interbloqueos. Para obtener más información, vea Minimizar los interbloqueos.

A menudo se confunden los interbloqueos con los bloqueos normales. Cuando una transacción solicita un bloqueo en un recurso bloqueado por otra transacción, la transacción solicitante espera hasta que se libere el bloqueo. De forma predeterminada, las transacciones de SQL Server no tienen tiempo de espera, a menos que se establezca LOCK_TIMEOUT. La transacción solicitante está bloqueada, no interbloqueada, porque la transacción solicitante no ha hecho nada para bloquear la transacción a la que pertenece el bloqueo. Finalmente, la transacción a la que pertenece el bloqueo se completará y liberará el bloqueo, y a la transacción solicitante se le concederá el bloqueo y continuará.

A veces, los interbloqueos se denominan "abrazo mortal".

Un interbloqueo es una condición que se puede dar en cualquier sistema con varios subprocesos, no sólo en un sistema de administración de bases de datos relacionales, y puede producirse para recursos distintos a los bloqueos en objetos de base de datos. Por ejemplo, un subproceso en un sistema operativo con varios subprocesos puede adquirir uno o más recursos, como bloqueos de memoria. Si el recurso que se desea adquirir pertenece actualmente a otro subproceso, puede que el primer subproceso deba esperar a que el otro libere el recurso de destino. En consecuencia, se dice que el subproceso que está en espera depende del subproceso que posee ese recurso concreto. En una instancia del Motor de base de datos, las sesiones pueden interbloquearse cuando adquieren recursos ajenos a la base de datos, como memoria o subprocesos.

Diagrama en el que se muestra un interbloqueo de transacciones

En la ilustración, la transacción T1 tiene una dependencia de la transacción T2 para el recurso de bloqueo de la tabla Part. Paralelamente, la transacción T2 tiene una dependencia de la transacción T1 para el recurso de bloqueo de la tabla Supplier. Puesto que estas dependencias forman un ciclo, hay un interbloqueo entre las transacciones T1 y T2.

Los interbloqueos también se pueden producir cuando se crean particiones en una tabla y el valor de LOCK_ESCALATION en ALTER TABLE se fija en AUTO. Cuando el valor de LOCK_ESCALATION es AUTO, la simultaneidad aumenta permitiendo a Motor de base de datos bloquear las particiones de la tabla en el nivel HoBT en lugar de en el nivel TABLE. Sin embargo, cuando transacciones independientes mantienen bloqueos de partición en una tabla y desean un bloqueo en algún punto de la partición de otras transacciones, se produce un interbloqueo. Este tipo de interbloqueo se puede evitar asignando a LOCK_ESCALATION el valor TABLE; aunque este valor reducirá la simultaneidad obligando a las grandes actualizaciones de las particiones a esperar a que se produzca un bloqueo de la tabla.