JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

¿Qué es un deadlock o interbloqueo?

Cuando se trabaja en programación paralela o multisubproceso, una palabra que sale a colación cada dos por tres es "deadlock" (o un "interbloqueo" en castellano). Muchos porgramadores principiantes tienen dudas sobre qué son y cómo se pueden producir, por lo que, a raíz de la pregunta de un alumno de mi curso de fundamentos de C# y .NET, me he decidido a escribir algo que lo explique de manera simple pero efectiva.

Un deadlock, es una situación difícil de reproducir, y se dará sólo en algunas circunstancias muy concretas, por eso son situaciones muy difíciles de prever y de depurar.

Un ejemplo clásico de interbloqueo es el de una cuenta bancaria.

Consideremos el caso de una clase para transferir dinero entre cuentas bancarias, algo así:

class Cuenta 
{ 
   double saldo;

   void Retirar(double cantidad) 
   { 
      saldo -= cantidad; 
   }

   void Ingresar(double cantidad) 
   { 
      saldo += cantidad; 
   }

   void Transferir(Cuenta cuentaOrigen, Cuenta cuentaDestino, double cantidad) 
   { 
      lock(cuentaOrigen) 
      { 
         lock(cuentaDestino) 
         { 
            cuentaOrigen.Retirar(cantidad); 
            cuentaDestino.Ingresar(cantidad); 
         } 
      } 
   } 
}

Este código no parece tener problema alguno, y parece bastante lógico.

DeadlockEn la operación de transferencia bloqueas el acceso a las clases que representan las cuentas de origen y destino para evitar inconsistencias en sus saldos, ya que si no lo bloquearas y otro hilo retira o ingresa dinero mientras se está efectuando otra transferencia podrías tener inconsistencias en los saldos. De esta forma te aseguras de que la operación de transferencia es consistente. Hasta aquí todo controlado...

Pero ¿qué pasa si de repente dos hilos intentan acceder exactamente al mismo tiempo a hacer una transferencia entre las mismas dos cuentas, pero en sentidos contrarios?

Por ejemplo:

Transferir(cuentaA, CuentaB, 1000);

y

Transferir(cuentaB, CuentaA, 500);

Lo que ocurriría es que la primera transferencia bloquearía la cuentaA y la segunda la cuentaB (es la primera línea de código). Al ir a bloquear la segunda cuenta, la primera operación se encontraría con un bloqueo en la cuentaB creado por la otra transferencia, y viceversa. El resultado es que ambas operaciones quedarían bloqueadas indefinidamente porque una estaría esperando debido al bloqueo de la otra: ¡deadlock!

Lo malo de esta situación es que se produce solamente en un caso muy concreto como el que describo, por lo que podríamos hacer nuestro programa, tenerlo en producción y que pasaran meses hasta que surgiera el problema. Y una vez que hubiera surgido no tendríamos forma de saber exactamente qué ha pasado ni ninguna pista de cómo reproducirlo. Por eso los problemas de multi-subproceso son tan complejos.

¡Espero que esto lo aclare un poco!

José Manuel Alarcón José Manuel Alarcón
Fundador de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Comentarios (5) -

Jorge Duarte Lopez

Muchas gracias por su explicación, fue muy fácil de entender e imaginar, estudio informática en el ultimo grado y esto fue una tarea de investigación, le agradezco su tiempo al hacer esto!.

Responder

Juan Carlos Casallas

Buenas tardes de antemano le doy las gracias por el aporte sobre los deadlock y como entender un poco mejor la forma de como se muestran ante el programa desarrollado mi duda seria de como puede afectar un problema de este tipo en una base de datos la cual este conectada con un proceso en una aplicación web.

Responder

by Jose M. Alarcon

Hola:

Los deadlocks o interbloqueos son una situación frecuente en las bases de datos muy solicitadas (o sea, con muchos usuarios simultáneos). En las bases de datos existen diferentes formas de establecer la conexión a la misma, el modo de lectura y de escritura y el modo de bloqueo utilizado. Según la base de datos la forma de gestionarlo y las capacidades son distintas. Es un tema complejo, aunque por defecto todas hacen un buen trabajo para las situaciones más comunes.

Si lo tuyo es SQL Server, en campusMVP tenemos un curso online interesante sobre trabajo con este gestor de bases de datos que, entre otras muchas cosas, trata también este tema: www.campusmvp.es/catalogo/Product-SQL-Server-práctico-para-desarrolladores_165.aspx

Saludos.

Responder

Oscar Garcia

Hola Jose muchas gracias por tu articulo. Te hago una consulta con respecto a la solución del problema planteado y es: ¿El patrón Singleton nos permite evitar caer en un deadlock como el que tu describes?

Responder

by Jose M. Alarcon

Hola Óscar:

No, un Singleton no te garantiza que no se vayan a producir deadlocks, todo depende de lo que haga el singleton y cómo accedas a él. Es más, sin un bloqueo previo  podría darse la paradoja de que un singleton se instanciasen dos veces si lo intentan dos subprocesos a la vez.

Por suerte en C# existe una estructura del lenguaje específicamente diseñada para evitar interbloqueos: lock.

docs.microsoft.com/.../lock-statement

Michael Shpilt ha lanzado hace poco un artículo bastante completo sobre todo este tema:

michaelscodingspot.com/.../

Yo solo trataba de explicar en qué consisten :-)

Saludos.

Responder

Agregar comentario