vtortola.Net

Junio 15, 2007

Modelo Asíncrono. Parte VI, deadlocks.

Archivado en: .NET, C#, Modelo Asíncrono — vtortola @ 10:20 pm

Siguiendo con el modelo asíncrono, un deadlock (bloqueo mortal ó de la muerte) sucede cuando dos ó más hilos intentan acceder a recursos que siempre estarán bloqueados, quedando ambos bloqueados en espera, pudiendo también causar el cuelgue total ó parcial de la aplicación.

Este diagrama de secuencia muestra el ejemplo más simple de deadlock, el hilo A bloquea el recurso X para su acceso exclusivo e intenta acceder a el recurso Y, a su vez el hilo B bloquea el recurso Y para su acceso exclusivo e intenta acceder al recurso X, esto provoca que ambos hilos queden esperando el uno al otro de forma indefinida.

 

Cuando uno de los hilos involucrados en el deadlock es el hilo principal de la aplicación, esta queda literalmente colgada, quedando totalmente congelada (freezed) si se tratase de una aplicación Windows Forms.

Los deadlocks pueden ser causados por cualquier técnica de sincronización para asegurar el acceso exclusivo a un recurso, y son provocados más por un diseño descuidado que por otra cosa, por ello debemos andar con sumo cuidado a la hora de bloquear nuestros recursos y realizar las pruebas necesarias pues no siempre son obvios, a veces se dan bajo un determinado número de circunstancias y variables, por lo que son difíciles de “debuggear”.

Este código ejemplifica un deadlock. Creo una lista de tareas que una vez lanzadas todas las llamadas asíncronas, recorro haciendo la espera de todos los hilos, bloqueándola primero para que nadie pueda modificar la lista mientras la recorro tal como hacia en el artículo sobre sincronización de tareas asíncronas. En la función correspondiente al ‘AsyncCallback’ elimino la tarea de la lista para que así el programa no tenga que hacer la espera de ese hilo. A priori parece una buena idea pero … MAAAL … mientras el hilo principal de la aplicación bloquea la lista de tareas haciendo el bucle de esperas, los hilos necesitan eliminar su correspondiente IAsyncResult de la lista para poder continuar, con lo que no finalizan nunca … y por lo tanto tampoco finaliza la espera del primer hilo que se esta haciendo en el bucle, de forma que la aplicación queda totalmente colgada y en idle, queda en deadlock.

private delegate void AsyncCallOut_(int p1);
private static AsyncCallOut_ AsynCallOut;
private static List<IAsyncResult> asyncTasks = new List<IAsyncResult>();
static void Main(string[] args)
{

AsynCallOut = new AsyncCallOut_(AsyncFuncOut);
for(int i=0;i<50;i++)
{

Console.WriteLine(“–> Lanzando tarea asíncrona “+ i.ToString());
asyncTasks.Add(AsynCallOut.BeginInvoke(i,
new AsyncCallback(FinAsyncFuncOut), i));

}


// Bloqueo la lista de tareas para acceso exclusivo…
lock (asyncTasks)
{

// Recorro la lista…
foreach (IAsyncResult ia in asyncTasks)
{

// Bloqueo el hilo actual hasta la finalización de este otro…
ia.AsyncWaitHandle.WaitOne();

}

}


// La aplicación nunca llegará a este punto.
Console.WriteLine(“FIN”);
Console.ReadKey();

}
private static void AsyncFuncOut(int p1)
{

Random rndm = new Random(p1);
System.Threading.
Thread.Sleep(rndm.Next(5000, 10000));
Console.Write(‘.’);

}
private static void FinAsyncFuncOut(IAsyncResult ia)
{

try
{

AsynCallOut.EndInvoke(ia);


// El hilo intentará acceder a la lista de tareas,
// pero al estar bloqueada tendra que esperar. Como no
// puede terminar su ejecución, tampoco lo hará la espera
// de arriba.
lock (asyncTasks)
{

asyncTasks.Remove(ia);

}
Console.WriteLine(“Fin de AsyncFunc #”+ ia.AsyncState.ToString());

}
catch (Exception Ex)
{

Console.WriteLine(Ex.Message);

}

}

No Comments Yet »

Aún no hay comentarios.

Canal RSS de los comentarios de la entrada. URI para TrackBack.

Deja un comentario

Debes ser Sesión como para publicar un comentario.

Blog de WordPress.com.