menú
¿Música de YouTube sin molestos comerciales? ¡Ahora es posible!
TubeFiesta es una aplicación que te permite reproducir música de YouTube como un reproductor tradicional.
Crear listas, reproducción aleatoria, repetir, y hasta exportar el video a otra pantalla.
Conocer más Ir a tfiesta.com

Utilizar un mismo objeto desde varios hilos con la instrucción lock c#

Publicado el 08/10/2013 | 4065 visitas

Hola, quienes hayan tenido la posibilidad de trabajar con múltiples hilos (Threads) se pudo haber enfrentado a con la dificultad de trabajar con un objeto al que muchos hilos tienen acceso, posiblemente obteniendo como resultado el famosisimo Colección modificada; puede que no se ejecute la operacion de enumeración técnicamente un InvalidOperationException.

Por qué? en que momento sucede?

Pues bien, primero entendamos el motivo de esta excepción:

Cuando tienes por ejemplo una lista estática en una clase que almacena unos productos específicos

public class Publicas
{
    public static List<Producto> ProductosDestacados
    {
        get;
        set;
    }
}

Y tienes dos subprocesos (hilos) diferentes en los que necesitas acceder y modificar esta lista:

Proceso 1 hace:

foreach(Producto p in Publicas.ProductosDestacados)
{
    //Agregar elementos tipo Producto a un GridView
}

Proceso 2 hace:

foreach(Producto p in Publicas.ProductosDestacados)
{
    if(p.ProductoId == 10)
        Publicas.ProductosDestacados.Remove(p);
}

Si el Proceso 1 estuviera en ejecución y el Proceso 2 elimina un elemento de la lista ProductosDestacados la colección o lista de elementos cambiaría provocando así que la sentencia foreach del Proceso 1 falle y salte la excepción.

Entonces cómo lo soluciono?

Para solucionarlo puedes hacer dos cosas: (Si conoces otra forma por favor indicala en los comentarios)

Utiliza for en vez de foreach:
Utilizando una sentencia for para recorrer la lista te evitas el problema porque únicamente utilizas esta lista para obtener un elemento por su indice; el foreach no la libera hasta que termina.

Utiliza la instrucción lock
La instrucción lock te permite garantizar que un subproceso no va a entrar en una sección crucial de código mientras otro subproceso ya se encuentre en ella. Genial no?

Y cómo utilizar la instrucción lock?

Veamos cómo se utiliza la instrucción lock en un sencillo ejemplo suponiendo el mismo caso anterior: Proceso 1 y Proceso 2:

Proceso 1 hace:

lock (Publicas.ProductosDestacados)
{
    foreach(Producto p in Publicas.ProductosDestacados)
    {
        //Agregar elementos tipo Producto a un GridView
    }
}

Proceso 2 hace:

lock (Publicas.ProductosDestacados)
{
    foreach(Producto p in Publicas.ProductosDestacados)
    {
        if(p.ProductoId == 10)
            Publicas.ProductosDestacados.Remove(p);
    }
}

Si no es suficientemente claro el ejemplo diría que si otro subproceso intenta entrar en un código bloqueado, esperará, o se bloqueará, hasta que el objeto se libere.

Riesgos al utilizar la sentencia lock

Aunque se ve muy bonito, practico y util, hay que tener mucho cuidado en excederse en el uso de la sentencia lock. En msdn dice claramente:

En general evite bloquear un tipo public o instancias que estén fuera del control de su código. Las construcciones comunes lock (this), lock (typeof (MyType)) y lock ("myLock") incumplen esta instrucción:

Mi recomendación es: No usar esta instrucción si el elemento bloqueado es utilizado por subprocesos cuyos bloqueos sean muy largos y a la vez el mismo elemento es utilizado por el mismo proceso de interfaz gráfica de la aplicación.

Espero sea de ayuda para alguien.

Talvez te interese...

Tutorial de sockets en c# con ejemplos - Parte 2 - UDP
Tutorial de sockets en c# con ejemplos - Parte 1
[solución] No puede obtener acceso a la página solicitada debido a la configuración de la extensión
[solución] El proveedor de almacenamiento especificado no se encuentra en la configuración
blog comments powered by Disqus