es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Bloqueo de múltiples objetos con conteo variable de objetos.

Tengo una matriz de mis propias clases, con tamaño N. Cada instancia puede hacer referencia a otras instancias en la matriz, y guarda una lista de índices en la lista.

class A
{
    public List<int> Referencias { get; } = new List<int>();
}

A[] a_array = new A[N];

Quiero crear un sistema de bloqueo inteligente – una matriz con tamaño N, donde en cada índice guardo un bloqueo para cada instancia en a_array. Siempre que actualizo o leo una instancia en a_array, necesito bloquear la instancia y todas sus referencias.

object[] bloqueos = new object[N];

foreach (var referencia in a.Referencias)
{
    // bloquear bloqueos[referencia];
}

¿Cómo bloqueo múltiples objetos en C#, cuando el número de bloqueos por instancia es variable (el número de referencias puede ser diferente para cada instancia de A)?

Sé que puedo usar Mutex para esto, pero quiero asegurarme de que el mutex se libera cada vez que se lanza una excepción en mi código.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una forma de lograrlo es mediante el uso de la declaración lock con un mecanismo de bloqueo personalizado. En lugar de usar un solo mutex para cada instancia, podemos usar un enfoque de bloqueo anidado, donde cada instancia A no solo mantiene una lista de índices, sino también una lista de bloqueos para cada uno de estos índices. Entonces podemos crear un objeto de bloqueo personalizado que asegure que todos los bloqueos se adquieran y liberen atómicamente, utilizando la clase Monitor en C#. Aquí hay una implementación de ejemplo:

    class A
    {
        public List<int> Referencias { get; } = new List<int>();
        public List<object> Bloqueos { get; } = new List<object>();
    }
    
    A[] arreglo_A = new A[N];
    object[] bloqueosGlobales = new object[N];
    
    // Inicialice los bloqueos para cada instancia A
    for (int i = 0; i < N; i++)
    {
        arreglo_A[i].Bloqueos.Add(bloqueosGlobales[i]); // agregar bloqueo para la instancia en sí misma
        foreach (var refer in arreglo_A[i].Referencias)
        {
            arreglo_A[i].Bloqueos.Add(bloqueosGlobales[refer]); // agregar bloqueo para cada referencia
        }
    }
    
    // Objeto de bloqueo personalizado para bloquear múltiples objetos atómicamente
    class BloqueoMultiple : IDisposable
    {
        private readonly object[] objetos;
        public BloqueoMultiple(params object[] objetos)
        {
            this.objetos = objetos;
            foreach (var obj in objetos)
            {
                Monitor.Enter(obj);
            }
        }
        public void Dispose()
        {
            foreach (var obj in objetos)
            {
                Monitor.Exit(obj);
            }
        }
    }
    
    // Método de actualización de ejemplo utilizando BloqueoMultiple
    void ActualizarA(int indice)
    {
        using (new BloqueoMultiple(arreglo_A[indice].Bloqueos.ToArray()))
        {
            // Realizar actualizaciones seguras para varios hilos de A[indice] y sus referencias
        }
    }
    

    La clase BloqueoMultiple crea un nuevo objeto de bloqueo que adquiere atómicamente todos los bloqueos para la instancia y sus referencias. Esto asegura que la instancia y todas sus referencias estén bloqueadas antes de realizar cualquier actualización, y que todos los bloqueos se liberen atómicamente, incluso si se produce una excepción. De esta manera, evitamos el riesgo de deadlocks causados por el bloqueo de un mutex a la vez, y nos aseguramos de que todos los bloqueos se liberen correctamente al final de la sección crítica.

Comments are closed.