martes, 29 de mayo de 2012

Utilización de la palabra Lock en aplicaciones Multihilo.

 

Muchas veces en aplicaciones multihilo, necesitamos controlar que mientras un hilo este ejecutando un método, otro hilo no vaya a ejecutar el mismo método hasta que el hilo1 termine de procesar el método, en otras palabra que el método no se ejecute al mismo tiempo por dos hilos diferentes.
Este tipo de bloqueo se puede realizar a través de una palabra reservada llamada LOCK , que como dije anteriormente no permitirá que un hilo vaya a entrar a un fragmento de código , mientras otro hilo lo este ejecutando, si un hilo intenta entrar al fragmento de código que se encuentra dentro de un LOCK, este hilo esperara a que el otro hilo termine.
La declaración de LOCK Hace un llamado al método Monitor.Enter y al finalizar al método Monitor.Exit con un try / Finally como se muestra a continuación:
Monitor.Enter (_locker);
try
{
  <procedimientos>
}
finally
{
Monitor.Exit (_locker);
}






Veamos el siguiente ejemplo en donde vamos a crear una aplicación de consola llamada Calculador_Thread la cual contiene una clase que tiene tres métodos que reciben dos números respectivamente e imprime la suma de dichos dos números, resta y multiplicación respetivamente.
clip_image002
en dicha clase creamos los métodos de la siguiente manera:
clip_image004
Creamos una detención de la ejecución de los hilos por un tiempo de 1 Segundo con Thread.Sleep(1000), para cada uno de los métodos en el main de la aplicación creamos un hilo de tal forma que cada operación sea realizada en un hilo diferente. El código de la aplicación main lo podemos visualizar a continuación:
clip_image005
Al ejecutar esta aplicación de esta forma podemos visualizar el siguiente resultado.
clip_image007
 
Fijemos que a pesar de la generación de la espera para la ejecución de los hilos el resultado de la variable resultado siempre es la multiplicación de dichos dos números, esto porque las operaciones se están ejecutando de manera paralela y la variable resultado puede ser modificada mientras dos hilos están ejecutándose al mismo tiempo. Que sucede si detenemos la aplicación y volvemos a ejecutarla?
clip_image009
Fijemos que debido a la ejecución multihilo, en algunos momentos un método se ejecuta antes que otro, a pesar de que el orden de ejecución de los hilos para este caso primero es la suma, luego la resta y por ultimo la multiplicación, sin embargo todo depende de que tan ocupado este el procesador donde se esta ejecutando el hilo creado. Sin comparamos la ejecución de la aplicación con respecto a la anterior vemos que el método de multiplicación se realizo en segundo lugar.
Utilicemos ahora la palabra reservada Lock la cual nos ayudara a que el fragmento de código sea ejecutado y nos alcance a presentar el valor de la variable resultado al imprimirla en pantalla , a pesar de que otro hilo este intentando modificar la variable resultado, de tal forma que el código de la clase operaciones quedara de la siguiente forma:
clip_image011
El resultado final cuando realizamos el bloqueo de la ejecución del fragmento de código es el siguiente:
clip_image013
Para finalizar este post es necesario que el desarrollador como buena práctica de la utilización de la palabra Lock nunca intente bloquear una variable pública ya que se convertiría en un problema para la administración de la varia

















jueves, 24 de mayo de 2012

MultiThread , Conceptos Generales


Para continuar con el tema de hilos y multihilos , vale la pena recordar que las aplicaciones concurrentes pueden correr sobre un computador que posee un solo procesador, pero las aplicaciones paralelas requieren de múltiples procesadores.
Cuando tenemos una aplicación que usa múltiples hilos en un computador que tiene un procesador con un solo núcleo, para el usuario los hilos aparentemente trabajan de forma paralela, pero lo que en realidad esta sucediendo es que el sistema operativo intercala los hilos, este comportamiento es llamado Interleaving (Intercalado), y el intercalamiento se basa sobre prioridades de hilos y otros factores que para este post no comentare, tal vez mas adelante profundizaremos sobre estos temas. En la actualidad existen dos tipos de paralelismo los cuales mecionare a continuación:
· Paralelismo Lógico: Cuando un procesador es compartido por varios hilos.
· Paralelismo Físico: Cuando en un equipo de computo existen varios procesadores con múltiples núcleo y el trabajo es descompuesto en tareas , y cada tarea es realizada por un procesador independientemente.




Para el intercalamiento de los hilos, al estar en ejecución un hilo, y si se quiera iniciar “al mismo tiempo la ejecución de otro hilo”, lo que hace el sistema operativo es que conserva el estado de esta hilo, lo detiene e inicia la ejecución del siguiente hilo y de esta manera trabaja el intercalamiento.

Para la ejecución de código paralelo como hemos visto requiere de múltiples núcleos , así que los hilos pueden ejecutarse en paralelo sin necesidad de intercalarse. Idealmente usted se deberia tiene un hilo por cada procesador disponible.


Veamos algunos ejemplos para la creación de hilos, teniendo en cuenta que el espacio en el framework .Net para el manejo de hilos es System.Threading. se puede crear un hilo de la siguiente forma:
Thread t = new Thread(metodo)
Los hilos comparte información si tienen una referencia común sobre el mismo objeto, en el siguiente ejemplo visualizaremos la impresión de un texto que se encuentra en el método impresión, y ejecutamos dos hilos, el hilo principal y el hilo secundaria.
 
   1:  class PruebaHilos
   2:   
   3:  {
   4:   
   5:  static void Main()
   6:   
   7:  {
   8:   
   9:  //Creacion de la instancia de la clase
  10:   
  11:  PruebaHilos tt = new PruebaHilos();
  12:   
  13:  // Creacion del hilo secundario, llamado al metodo Impresion e inicio de ejecucion del Hilo
  14:   
  15:  new Thread(tt.Impresion).Start();
  16:   
  17:  //ejecucion de Hilo Principal, Que llama al metodo Impresion
  18:   
  19:  tt.Impresion();
  20:   
  21:  Console.ReadLine();
  22:   
  23:  }
  24:   
  25:  // Create a common instance
  26:   
  27:  // Note that Go is now an instance method
  28:   
  29:  void Impresion()
  30:   
  31:  {
  32:   
  33:  Console.WriteLine("Ejecucion de Hilo");
  34:   
  35:  }
  36:   
  37:  }



El resultado de este proyecto es que cuando se ejecuta tanto el hilo primario como el hilo secundario, los cuales llaman a método impresión, imprimirá dos veces la palabra YaPaso, como aparece a continuación.

clip_image002

En el siguiente ejemplo lo que veremos es la creación de una variable de tipo boolean la cual comparte información en la ejecución de los dos hilos, dicha variable será controlada desde el método, en donde si un hilo ya paso por el método , entonces la variable será modificada a un valor true y solo se imprimirá una sola vez la palabra ejecución de Hilo, con este pequeño ejemplo lo que podemos verificar es que los hilos comparte información entre si con respecto a las variables.
   1:  class PruebaHilos
   2:   
   3:  {
   4:   
   5:  static bool YaPaso;
   6:   
   7:  static void Main()
   8:   
   9:  {
  10:   
  11:  //Creacion de la instancia de la clase
  12:   
  13:  PruebaHilos tt = new PruebaHilos();
  14:   
  15:  // Creacion del hilo secundario, llamado al metodo Impresion e inicio de ejecucion del Hilo
  16:   
  17:  new Thread(tt.Impresion).Start();
  18:   
  19:  //ejecucion de Hilo Principal, Que llama al metodo Impresion
  20:   
  21:  tt.Impresion();
  22:   
  23:  Console.ReadLine();
  24:   
  25:  }
  26:   
  27:  //Metodo que imprime Ejecucion de Hilo
  28:   
  29:  void Impresion()
  30:   
  31:  { 
  32:   
  33:  if (!YaPaso) 
  34:   
  35:  {
  36:   
  37:  YaPaso = true; 
  38:   
  39:  Console.WriteLine("Ejecucion de Hilo");
  40:   
  41:  }
  42:   
  43:  }
  44:   
  45:  }
  46:   




El resultado de este ejemplo es el siguiente:

clip_image004

En el trabajo con hilos (Threads) o subprocesos existen términos importantes que debemos manejar
Algunos términos importantes:

Sobre-subscripcion: ocurre cuando el numero de hilos excede el numero de procesadores disponibles. Cuando esto sucede el intercalado ocurre para los hilos que comparten un solo procesador.

Sub-Suscripcion: ocurre cuando hay un numero menor de hilos que procesadores disponibles, cuando esto pasa existen procesadores inactivos y una menor utilización optima de CPU.
Desde luego la meta es la utilizar al máximo la CPU, mientra exista un balance entre la sobre-suscripcion y sub-subscripcion

Un hilo puede correr sobre dedicado a un procesador o atraves de otros procesadores. Los hilos ejecutados por un solo procesador poseen una afinidad de procesador, y esto hace que sea mas eficiente.

La programación y lanzamiento en ejecución de un hilo sobre otro nucleo de procesador causa perdidas de cache, acceso local de memoria como resultado de perdida de cache, y exceso de swticheo. Esto es llamado cross- Core swtich.

Sincronizacion.

La sincronización es la herramienta mas común usada para crear ambientes para hilo seguro Thread-Safe de hilo, donde se encuentra el modo Kernel y modo usuario.
Multihilo implica creación de multiples hilos. Los pasos requeridos para la creación de hilos son relativamente sencillos, pero es necesario tener cuidado con la gestión de los hilos ya que manejar aplicaciones Multihilo implica un manejo mas complejo que las aplicaciones tradicionales
Por ejemplo una aplicación con un solo hilo es sincronizada con los recursos de modo Kernel.
Compartir información es la segunda razón para la contención entre multiples hilos y los requerimiento de sincronización.
La contención ocurre cuando un hilo no puede obtener una sicronizacion de objetos o acceso a información compartida durante un periodo de tiempo. Los hilos típicamente se bloquean hasta que la entidad este disponible.
Un tipo de bloqueo es el llamado spinning. Las aplicaciones tienen la opción de spinning en modo usuario, consumen ciclos de CPU pero evitan el switcheo en modo Kernel. Despues de un corto tiempo, el hilo puede volver a intentar adquirir el recurso que es compartido. Si la contesion es corta, se puede adquirir con éxito el recurso sobre el segundo intento para evitar el bloqueo y el switcheo en el contexto relacionado.
Spining para sincronización es considerado un sincronización ligera, Microsoft ha adicionado tipo tales como la estructura SPINWAIT de Framework de .net para este propósito, por ejemplo spining es usado para colecciones concurrentes importante considerar el espacion de nombres System.Collection.Concurrent, para crear hilo seguros y colleciones libres de bloqueos.
Las aplicaciones paralelas se basan se alguna manera en sincronización,. Aveces consideramos que la sincronización es un mal necesario. El exceso uso de sincronización es malo, porque las aplicaciones en paralelo funcionan mejor sin impedimento de cualquier tipo. Serializar una aplicación paralela va en contra de un buen desempeño de la aplicación. De hecho la mejora de la velocidad de una aplicación en paralelo depende de gran parte que porción de código se ejecuta secuencialmente. Por ejemplo cuando una aplicación corre un 40% de forma secuencial, el valor máximo posible de velocidad que puede proveer en teoría seria de un 60%.
En el proximo post hablare de una palabra reservada llamada lock la cual es usada de alguna forma para sincronizar la utilización de hilos en aplicaciones multihilo.

miércoles, 9 de mayo de 2012

Procesos, Hilos (Threads- Subproceso), MultiHilos (MultiThreads)

 

Buen dia para todos, con el fin de continuar la serie de blogs de hilos y paralelismo a continuación quiero compartir con ustedes algunas definiciones importantes antes de iniciar con el tema de computación en paralelo, definiciones básicas como que es un proceso?, diferencia entre hilos y multihilos, y finalmente algunas de las funcionalidades que trae el Framework de .Net para la gestión y manejo de hilos.

Procesos.

Un hilo representa básicamente una acción de un programa, un proceso en si mismo no hace nada, en su lugar hospeda los recursos consumidos de la aplicación que se esta ejecutando, tal como el head y la pila de memoria en otras palabras proporciona los recursos necesario para que un programa pueda ejecutarse.

Un proceso contiene un espacio de memoria virtual, código, ejecutable, un contexto de seguridad, un identificador de proceso único, variables de entorno, y al menos un thread de ejecución.

Cada proceso se inicia con un único thread, a menudo llamado thread principal, pero puede crear threads adicionales. (Ver Ilustración 1)

clip_image002

Ilustración 1

Threads

Un hilo es una posible forma de ejecutar un programa, además es la entidad dentro de un proceso que realmente ejecuta el código contenido en el proceso.

Es importante tener en cuenta que todos los threads de un proceso comparten los recursos y memoria virtual de proceso, cada Thread mantiene los controladores de excepciones, una prioridad de programación, almacenamiento local y un identificador de Thread Único.

Un proceso puede contener uno o mas Threads, a mas threads tenga un proceso va a dar la sensación de que dicho proceso esta ejecutando varias tareas al mismo tiempo. (Ver Ilustración 2).

clip_image004

Ilustración 2

A continuación presentamos un ejercicio sencillo en donde se puede visualizar como se crea un hilo en C# y como interactúa un hilo principal y un hilo secudario.

   

   1:  using System;
   2:  using System.Threading;
   3:   
   4:  namespace Hilos1
   5:  {
   6:      class Program
   7:      {
   8:          static void Main(string[] args)
   9:          {
  10:              Thread t = new Thread(HiloSecundario);
  11:              t.Start();
  12:              while (true)
  13:                  //Hilo principal
  14:                  Console.Write("1");
  15:          }
  16:   
  17:          static void HiloSecundario()
  18:          {
  19:              //Escribe y indefinidamente
  20:              while (true)
  21:                  Console.Write("2"); 
  22:          }
  23:   
  24:      }

25: }

clip_image006




En este ejercicio el hilo principal crea un nuevo hilo llamado t el cual ejecuta un método llamado hilosecundario, sobre el cual se ejecuta la impresión del numero 2, simultáneamente el hilo principal imprime el numero 1. EL CLR asigna a cada hilo su propia pila de memoria para que las variables locales se mantengan de forma separada.

 

MultiThread


Una de las características innovadoras e interesantes es la incorporación de la programación multihilo (MultiThreading) . Cuando se ejecuta una aplicación que Multihilo, cada hilo ejecuta funciones de forma separada, y podemos afirmar que el multithreading es una forma especializada de la multitarea.

En la siguiente grafica podemos visualizar como funcionan las aplicaciones MultiHilo, las cuales permiten realizar tareas asíncronas “al mismo tiempo”, aunque realmente no es asi. Por ejemplo para el proceso de paint el sistema operativo le sede el control al hilo 1 de paint , y luego sede el control al siguiente Thread y asi sucesivamente.

clip_image008


Según la grafica el primer proceso ha tenido mucho mas tiempo de CPU que el resto de los procesos, lo que puede indicar que el proceso de paint ha hecho mas cosas en el mismo tiempo que los demás procesos. Sin embargo como solo tenemos un solo Core , sencillamente cada hilo se va a ejecutar de uno en uno, cada Threads.

Multithreading es manejado internamente por un programador de hilos (Thread scheduler), una función típica del CLR es delegarlo al sistema operativo. Un programador de hilos (Thread scheduler) asegura que todos los hilos activos sean asignados apropiadamente en tiempo de ejecución, y que los hilos que se encuentran en espera o bloqueados no consuman tiempo de CPU.

En un equipo con un solo núcleo el programador de hilos, hace que se conmuten los hilos activos, realizando una especie de multiplexacion, en un equipo con Windows el tiempo de conmutación entre hilos es de aproximadamente 10 ms.


A medida que se aumentan lo core en el hardware, lo que produce es que cada un hilo puede ejecutarse de forma paralela, ya que un hilo podrá ejecutarse en un procesador y el otro hilo en el otro procesador, lo que conlleva a que exista paralelismo. Solo puede existir paralelismo cuando existe mas de un core en el hardware.

clip_image010


,

Es importante conocer que actualmente existen dos tipos distintos de multitarea:


a) Basada en Procesos.

b) Basada en la ejecución de Hilos (Subprocesos).


A continuación presento a ustedes alguna de las diferencias de multitarea basada en proceso y basada en hilos (Threads - Subproceso).

La multitarea basada en procesos se encarga de la ejecución concurrente de los programas, mientras que la multitarea basado en hilos realiza acuerdos para la ejecución simultánea de las partes de un mismo programa.

Basado en procesos: Ejemplo - procesador de textos corriendo al mismo tiempo que se navega por la red.

Basado en Hilos (Subproceso): en un programa como Paint se puede dar formato a un color de un dibujo, al mismo tiempo que se está imprimiendo.

La diferencia clave es que los procesos están completamente aislados unos de otros, los hilos comparten el head de memoria con otros hilos que se ejecutan sobre la misma aplicacion. Esto es lo que hace que los hilos sean útiles : un hilo se puede ir a buscar los datos en segundo plano, mientras que otro hilo muestra los datos a medida que van llegando.



Importante tener en cuenta: Las aplicaciones paralelas son concurrentes, pero no toda aplicación concurrente es paralela.

El Framework de .Net trae consigo la funcionalidad de poder gestionar los hilos con la librería using System.Threading, y define dos tipos de hilos, Primer plano. (Foreground), Segundo plano. (BackGround). De forma predeterminada cuando se crea un hilo, se trata de un subproceso de primer plano, pero se puede cambiar a un subproceso en segundo plano. La única diferencia entre un hilo primer plano y el hilo de segundo plano, es que un hilo de segundo plano se cancelará automáticamente cuando todos los Hilos en primer plano son detenidos en su proceso.

Todos los procesos tienen al menos un hilo de ejecución, generalmente se llama el hilo principal, ya que es el que se ejecuta cuando el programa comienza. Desde el hilo principal se pueden crear otros hilos.