miércoles, 9 de mayo de 2012

Refactorizando código de sección crítica con AOP y PostSharp

La sincronización expuesta aquí se basa en los procesos y nos referimos a ella por el hecho de que esta otorga varias técnicas de coordinación de hilos que se ejecutan en forma simultánea y procesos para poder completar una determinada tarea con el objetivo de que estas se ejecuten en un orden establecido y que no se dé lugar a eventos inesperados.


Mencionamos a continuación en forma general los tipos de sincronización existentes: Barrier, Bloqueo/Semáforo (Lock/Semaphore), Unión de hilos (Thread join), Exclusión Mutua (Mutex), Monitores (Monitors), Sincronización no bloqueante (Non-blocking synchronization), Rendezvous, Contadores de eventos y secuenciadores (Event counters and sequencers).

Utilizaremos el tipo de sincronización basado en Exclusión Mutua de acuerdo al código de ejemplo que expondremos seguidamente, dicho ejemplo se encuentra codificado en C# .net sin la utilización de aspectos:


Ejemplo de Sincronización sin AOP para Exclusión Mutua

public void SynchronizedMethod()
{
        lock(this)
       {
               //.. hacer algo, esta es una sección //crítica de código o de exclusión mutua
       }
}

Y más abajo exponemos lo mismo pero en su presentación en AOP a través de un atributo llamado Synchronized:


Ejemplo de Sincronización en AOP para Exclusión Mutua con PostSharp

[Synchronized]
public void SynchronizedMethod()
{
         //.. hacer algo, esta es una sección crítica de //código o de exclusión mutua
}

Básicamente la idea es hacer un código más elegante y a la vez más fácil de leer por parte de algún programador y mediante la utilización de los atributos se logra este objetivo. Finalmente colocamos la definición del aspecto de sincronización en el fragmento de código siguiente valiéndonos del framework PostSharp orientado a AOP:

Definición de Aspecto de Sincronización en AOP con PostSharp

[Serializable]
public class SynchronizedAttribute : OnMethodBoundaryAspect
{
         public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
                Monitor.Enter(eventArgs.Instance);
        }

        public override void OnExit(MethodExecutionEventArgs eventArgs)
       {
               Monitor.Exit(eventArgs.Instance);
       }
}


Con esto nos ahorramos el hecho de colocar en cada método la palabra clave lock, el cual garantiza la ejecución de una sección crítica de código o exclusión mutua también denominada, una sección crítica de código es aquella que no permite ser ejecutada al mismo tiempo, debido a que puede darse el caso de que haya lectura sucia o que al mismo tiempo dos o más hilos de ejecución traten de modificar el valor de una variable, por lo tanto se bloquea dicha sección de código en forma exclusiva en un ambiente concurrente, no permitiendo de esta forma a que otro hilo trate de ejecutar esa sección crítica en un instante dado.

Además al evitar repetir esta palabra clave nos aseguramos de no repetir código por un lado y por otro de separar la funcionalidad básica del aspecto de sincronización.

En la definición del aspecto de sincronización expuesto más arriba, podemos decir que existen dos métodos, el primero llamado OnEntry el cual habilita la entrada a la ejecución del código de sección crítica y se utiliza la clase Monitor que provee un mecanismo para sincronizar el acceso a los objetos y el segundo método llamado OnExit, que se usa para realizar el abandono de la sección crítica de la ejecución del código, por lo tanto se invoca al método Exit de la clase Monitor.




No hay comentarios:

Publicar un comentario