You are on page 1of 12

PROGRAMACION DE HILOS Al escuchar la palabra multi-hilo, tal vez lo primero que te viene a la mente son muchos "hilos" de los

que conocemos normalmente en casa, pero al hablar en trminos de programacin, no nos estamos refiriendo a esos "hilos". En programacin, nos estamos refiriendo a los lenguajes de programacin que permiten la ejecucin de varias tareas en forma simultnea. Por ejemplo, consideremos la cantidad de aplicaciones que corren a la vez dentro de un mismo entrono grfico. Mientras una persona escribe un documento, esta corriendo Microsoft Windows adems de Internet Explorer, Windows Explorer, CD Player y el Control de Volmen. Estas aplicaciones son ejecutadas dentro de alguna versin de Windows. De esta forma, podemos pensar que los procesos son anlogos a las aplicaciones o a programas aislados, pero realmente tiene asignado espacio propio de ejecucin dentro del sistema. Java, es un lenguaje multihilo, ya que permite la ejecucin de varias actividades en forma simultnea, tanto en un programa creado en este lenguaje como en el corazn mismo del lenguaje (en la parte interna). Teniendo como resultado, que se pueden usar hilos Java como standard, en cualquier plataforma. 3.1 Concepto de hilo. Los hilos o threads, son bsicamente, pequeos procesos o piezas independientes de un gran proceso. Tambin podemos decir, que un hilo es un flujo nico de ejecucin dentro de un proceso (un proceso es un programa ejecutndose dentro de su propio espacio de direcciones). Un hilo no puede correr por s mismo, se ejecuta dentro de un programa, ya que requieren la supervisin de un proceso padre para correr. Se pueden porgramar mltiples hilos de ejecucin para que corran simultneamente en el mismo programa. La utilidad de la programacin multihilo resulta evidente. Por ejemplo, un navegador Web puede descargar un archivo de un sitio, y acceder a otro sitio al mismo tiempo. Si el navegador puede realizar simultneamente dos tareas, no tendr que esperar hasta que el archivo haya terminado de descargarse para poder navegar a otro sitio. Los hilos a menudo, son conocidos o llamados procesos ligeros. 3.2 Comparacin. Un thread o hilo es, al igual que un proceso, un flujo de control que puede gozar de cierta autonoma (puede tener sus propias estructuras de datos), pero a diferencia de un proceso, diversos hilos dentro de una aplicacin pueden compartir los mismos datos. El beneficio de ser multihilo, consiste en un mejor rendimiento interactivo y un mejor comportamiento en tiempo real. Aunque el comportamiento en tiempo real, esta limitado a las capacidades del sistema operativo sobre el que corre, an supera a los entornos de flujo nico de programa (single-thread) tanto en facilidad de desarrollo, como en rendimiento. Mientras los procesos mantienen su propio espacio de direcciones y entorno de operaciones, los hilos dependen de un programa padre en lo que se refiere a recursos de ejecucin. En Java, los hilos comparten el mismo espacio de memoria. Incluso comparten gran parte del entorno de ejecucin, de modo que la creacin de nuevos hilos es mucho ms rpida que la

creacin de nuevos procesos. La ventaja que proporcionan los hilos, es la capacidad de tener ms de un camino de ejecucin en un mismo programa. 3.3 Creacin y control de hilos. 3.3.1. Atributos de hilos. Los atributos o propiedades de un hilo varan de una implementacin a otra. Sin embargo, de forma general los atributos que definen un thread son: Estado de espera: permite que otros hilos, esperen hasta que termine de ejecutarse un hilo en especial. Direccin de stack. apuntador al inicio del stock del hilo. Tamao de la direccin: longitud del stock del hilo. Alcance (scope): define quien controla la ejecucin del hilo: el proceso o el ncleo del sistema operativo. Herencia: los parmetros de calendarizacin son heredados o definidos localmente. Poltica de calendarizacin: se define que proceso se va a ejecutar y en qu instante. Prioridad: un valor de prioridad alto corresponde a una mayor prioridad.

3.3.2. Creacin de hilos. En Java, existen dos mecanismo que nos permiten la creacin de hilos: Implementando la interfaz Runnable Extendiendo la clase Thread, es decir, creando una subclase de sta.

En cualquiera de los dos casos, se debe definir un mtodo run que ser el que incluya las instrucciones que se ejecutarn en el thread (hilo) y se pueden definir prioridades aunque no se puede confiar en que la mquina virtual escoja para ejecutar, siempre, el de mayor prioridad, por lo que no se pueden utilizar para basar en ellas el scheduler de un sistema en tiempo real. La clase Thread. class Repeticion extends Thread { private int repeticiones; private String mensaje; Repeticion (String msg, int n) { mensaje = msg; repeticiones = n; } public void run() { for (int i= 1; i <= repeticiones; i++) System.out.println (mensaje + " " +i); } public static vouid main (String args [ ] { Repeticion r1 = new Repeticion ("Rojo", 5); Repeticion r2 = new Repeticion ("Azul", 80); r1.start(); r2.start(); } } Cuando creamos un hilo extendiendo la clase Thread, se pueden heredar los mtodos y variables de la clase padre. Si es as, una misma subclase solamente puede extender o drivar una vez la

clase padre Thread. Esta limitacin de Java puede ser superada a travs de la implementacin de Runnable que es una interfaz. La interfaz Runnable. class Repeticion2 implements Runnable { private int repeticiones; private String mensaje; Repeticion2 (String msg, int n) { mensaje = msg; repeticiones = n; } public void run ( ) { for (int i=1; i<= repeticiones; i++;) System.out.println(mensaje + " " + i); } public static void main (String args [ ]) {

Repeticion r1 = new Repeticion ("Rojo", 5); Thread r2 = new Thread (new Repeticion2 ("Azul", 80)) r1.start (); r2.start (); } }
3.3.3. Arranque de hilos. Como se pudo apreciar en los ejemplos anteriores, el arranque de un hilo debe realizarse dentro del mtodo principal de Java, que como todos sabemos, es el mtodo main. Y lo arrancamos llamando al mtodo start. r1.start ( ); start, es el mtodo oculto en el hilo cuya funcin es llamar al mtodo run. 3.3.4. Manipulacin de hilos. Una vez que realizamos la creacin de un hilo, ste debe contener una traza de ejecucin vlida, la cual controlaremos en el mtodo run del objeto. El cuerpo de sta funcin (las acciones del hilo), vienen a ser el cuerpo del programa. Es como referirnos a la rutina main pero a nivel del hilo. Es decir, todas las acciones que nos interesa que nuestro hilo realice, deben estar especificadas en el mtodo run. Al terminar de ejecutarse el mtodo run, tambin terminar la ejecucin de nuestros hilos. Por lo anterior, la manipulacin de nuestro hilos, se realiza dentro del mtodo run. 3.3.5. Suspensin de hilos. Tambin podemos realizar la suspensin de un hilo, es decir, detenerlo o desactivarlo por un intervalo de tiempo indeterminado, para sto utilizamos la funcin suspend. Este mtodo no detiene la ejecucin en forma permanente. El hilo es suspendido indefinidamente y para volver a activarlo nuevamente es necesario realizar una invocacin a la funcin resume.

Es importante mencionar, que tambin existe la funcin sleep, pero en sta se especifica el tiempo en milisegundos en el que el hilo permanecer "dormido" y al trmino de ste tiempo el hilo continua ejecutndose. 3.3.6. Parada de hilos. El mtodo que debemos utilizar para detener la ejecucin de nuestro hilo, es stop, el cual detendr la ejecucin en forma permanente. t1.stop(); Este mtodo no destruye el hilo, simplemente detiene su ejecucin y sta no puede ser reanudada con el mtodo start. Su utilidad tiene sentido, sobre todo, en aplicaciones complejas que necesiten un control sobre cada uno de los hilos que se ejecuten. 3.4. Sincronizacin de hilos. La necesidad de la sincronizacin de hilos, tiene lugar cuando varios hilos intentan acceder al mismo recurso o dato. Es decir, los hilos necesitan establecer cierto orden, a la hora de acceder a datos comunes. Para asegurarse de que los hilos concurrentes no se estorban y operan correctamente con datos o recursos compartidos, un sistema estable previene la inacicin y el punto muerto o interbloqueo. La inanicin tiene lugar cuando uno o ms hilos estn bloqueados al intentar conseguir el acceso a un recurso compartido de ocurrencias limitadas. El interbloqueo es la ltima fase de la inanicin; ocurre cuando uno oms hilos estn esperando una condicin que no puede ser satisfecha. Esto ocurre muy frecuentemente cuando dos o ms hilos estn esperando a que el otro u otros desbloqueen algn dato u objeto comn. Existen dos forma para aplicar la sincronizacin: Bloqueo de objetos Uso de seales.

Bloqueo de objetos. Un objeto es bloqueado para indicarle a los dems hilos que estan en ejecucin y que pudieran intentar acceder a ste que ya un hilo lo esta utilizando, para esto utilizamos la palabra synchronized en la definicin de los mtodos que tienen la posibilidad de tener ste problema de sincronizacin, por ejemplo: public synchronized int getNumero(); De sta forma, cuando un objeto este ejecutando el mtodo getNumero que utiliza synchronized, se establece un bloqueo en dicho objeto para que ningn otro hilo pueda utilizarlo hasta que termine de ser usado por el hilo actual. Uso de semforos o seales. Dentro de ste sistema, un hilo puede detener su ejecucin y esperar una seal de otro hilo para continuar con su ejecucin. En este sistema encontramos varios sistemas como son el uso de mutex, semforos y barreras. 3.4.1. Mutex.

Tambin conocida como cerraduras de exclusin mutua, se utilizan para implementar secciones crticas y proteger las estructuras de datos compartidas contra accesos concurrentes. Se dice que las variables mutex, es la forma ms fcil de implementar la sincronizacin de hilos y de proteger recursos compartidos cuando acontecen multitud de intentos de acceso sobre esos recursos. Dicha "proteccin" la realizan al "cerrar el candado o cerradura" para no permitir el acceso. Solo un hilo puede cerrar un candado en un determinado instante. Incluso si varios hilos intentan cerrar el mismo candado solo uno saldr victorio. Ningn otro hilo podr poseer dicho recurso hasta que el hilo que lo cerr lo abra. 3.4.2. Semforos. En el caso de los semforos, podemos establecer un nmero mximo de hilos que pueden tener acceso simultneo a un recurso compartido en especfico; es decir, es una variable especial que constituye el mtodo clsico para restringir o permitir el acceso a recursos compartidos. Cada vez que un hilo intenta utilizar el recurso compartido, existe un contador que se va decrementando en uno y lo deja pasar. En el momento en que el contador se convierte en cero, deja bloqueado al hilo que intent el acceso. Inicia(Semforo s, Entero v) { s = v; // Declara el contador de tipo entero } P(Semforo s) { if(s>0) // Si an no se ha excedido el nmero permitido deja pasar el hilo s = s-1; // Decrementa el contador else // Si ya se tiene el nmero permitido de hilos ejecutndose wait(); // Deja el hilo en espera } V(Semforo s) { if(!procesos_bloqueados) s = s+1; else signal(); } Un tipo simple de semforo es el binario, que puede tomar los valores de 0 y 1. Se inicializa en 1 y son usados cuando solo un proceso puede acceder a un recurso a la vez. Son esencialmente lo mismo que el mutex. 3.4.3. Barreras (Barrier). Las barreras son otro mtodo de sincronizacin, y el ms fcil de entender. Una barrera es un punto de encuentro entre varios hilos, en donde todos los hilos ejecutan una accin o diferentes acciones hasta llegar al barrier o punto de encuentro, una vez que han llegado todos los hilos, stos pueden continuar con su ejecucin. Esto se utiliza generlamente, cuando una aplicacin funciona por fases.

La clave en ste mtodo de sincronizacin es el mtodo wait() que har que los hilos esperen hasta la llegada de todos. Un hilo es un subconjunto de sentencias de un programa con un objetivo especfico. En un procesador con varios nucleos son ejecutados concurrentemente por cada nucleo; por lo tanto supone una mejora en la rapidez de ejecucin de un programa. Programar en hilos en procesadores multinucleo aprovecha la ejecucin simultanea de varias partes del mismo programa por nucleos distintos,pudiendo accesar cada hilo de forma compartida variables del programa ("variables globales"). Algunos autores llaman cdigos secuenciales a los que no usan hilos y cdigos paralelos a los que s los usan. Secuenciales porque debe de esperar cada actividad a que termine su antecesora; independientemente de si esta actividad es requisito previo o no para su ejecucin. [apendice A] Notas: (1) Hilo en ingls es Thread, este trmino se usar en forma de sinnimo en ocasiones, dado que C# lo utiliza para definirlos. (2) Algunos textos sern sustentados por ejemplos con cdigo ejecutable ya probado, solo hay que ir a la referencia que se indicar con corchetes. C# provee su namespace System.Threading para su soporte. En l distingue dos tipos de hilos: (a) Ejecutados en primer orden -> foreground Los hilos de forma predeterminada corresponden a esta categora. (b) Ejecutados en segundo plano -> background Su caracterstica peculiar es que terminan automticamente cuando han terminado todos lo hilos de tipo foreground del proceso. Para generarse hay que cambiar la propiedad IsBackground a True. Tal y como un proceso que pasa por varios estados los hilos tambin,sus estados son: (1) Running (2) StopRequested (3) SuspendRequested (4) Background (5) Unstarted (6) Stopped (7) WaitSleepJoin (8) Suspended (9) AbortRequested (10) Aborted El siguiente enlace en espaol del MSDN da una explicacin de cada uno de dichos estados [1] Los hilos en C# pueden generarse definiendo para cada hilo un punto de entrada. qu es esto? Un punto de entrada es un mtodo de una clase que inicia la ejecucin de un hilo; pueden existir distintos puntos de entrada para distintos hilos en una misma clase. Estos mtodos deben tener las siguientes caractersticas: (a) Pblicos

(b) No regresan un resultado (void ) De lo contrario se generar un error al momento de compilar la clase. Los mtodos que pueden ser puntos de entrada pueden ser estticos o no. Si son estticos no tiene que generarse un objeto de la clase a la que pertenecen [apndice B], de lo contrario si debe de generarse el objeto previamente [apndice C]. Nota: Los mtodos estticos por definicin deben de ser pblicos, pero los mtodos de instancia No necesariamente. C# permite definir puntos de entrada como mtodos de instancia privados.[apndice D] Al punto de entrada se le pueden pasar parmetros, pero este solo puede ser uno, de la clase object [apndice E]. Si se quieren pasar mltiples datos solo hay que generar una clase que sirva de transporte para ellos [apndice F]. A continuacin el proceso de creacin de un hilo realizado por pasos: ( 1 ) Se genera un objeto de la clase Thread que controlar el hilo y que recibe como parmetro en su constructor la referencia del mtodo que va a ejecutar como punto de entrada del hilo. Thread h = new Thread( ); puede ser: Un mtodo esttico o uno de instancia. Clase.metodo -> para un mtodo esttico [apndice B] objeto.metodo -> para un mtodo de instancia [apndice C] ( 2 ) Iniciar el objeto hilo que se acaba de generar, invocando al mtodo Start. h.Start(); Si el mtodo recibe un parmetro de tipo object este debe de indicarse ahora [apndice F]. Referencias [1] MSDN Library, ThreadState. enlace Describe los estados que puede tener un hilo en .NET [2] Wilsonmar. Thread programming. enlace Realiza comparaciones entre distintos lenguajes para programar en hilos. [3] Anita May Joseph. Introducing multithreaded programming in C#. enlace [4] MSDN Library, ParameterizedThreadStart. enlace Muestra ejemplos y describe la clase ParameterizedThreadStart, que se utiliza para definir un punto de inicio de un hilo con parmetros. Apndices Apndice A Cdigo ejemplo, realizando en forma secuencial. No utiliza hilos.Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000

using System; using System.Threading; namespace codigosEjemplo { public class ejemplo1 { public void calculaPares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0}", cont); } public void calculaImpares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("Impares {0}", cont); } public static void Main() { ejemplo1 obj1= new ejemplo1(); System.Console.WriteLine("pares hasta el 500,000"); obj1.calculaPares(); obj1.calculaImpares(); } } }

Apndice B Cdigo ejemplo, realizando en forma paralela. Utiliza hilos. Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000 . El punto de entrada al hilo es un mtodo esttico.

using System; using System.Threading; namespace codigosEjemplo { public class ejemplo1 { public static void calculaPares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0}", cont); } public static void calculaImpares()

{ int cont=0; for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("Impares {0}", cont); } public static void Main() { //ejemplo1 obj1= new ejemplo1(); System.Console.WriteLine("pares hasta el 500,000"); Thread t1= new Thread( ejemplo1.calculaPares ); Thread t2= new Thread( ejemplo1.calculaImpares ); t1.Start(); t2.Start(); } } }

Apndice C Cdigo ejemplo, realizando en forma paralela. Utiliza hilos.Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000 . El punto de entrada al hilo es un mtodo de instancia.

using System; using System.Threading; namespace codigosEjemplo { public class ejemplo1 { public void calculaPares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0}", cont); } public void calculaImpares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("Impares {0}", cont); } public static void Main() { ejemplo1 obj1= new ejemplo1(); System.Console.WriteLine("pares hasta el 500,000"); Thread t1= new Thread( obj1.calculaPares ); Thread t2= new Thread( obj1.calculaImpares ); t1.Start(); t2.Start();

} } }

Apndice D Cdigo ejemplo, realizando en forma paralela. Utiliza hilos. Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000 . El punto de entrada al hilo es un mtodo de instancia que es privado, pero an as compila el cdigo y lo ejecuta correctamente.

using System; using System.Threading; namespace codigosEjemplo { public class ejemplo1 { //public void calculaPares() private void calculaPares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0}", cont); } //public void calculaImpares() private void calculaImpares() { int cont=0; for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("Impares {0}", cont); } public static void Main() { ejemplo1 obj1= new ejemplo1(); System.Console.WriteLine("pares hasta el 500,000"); Thread t1= new Thread( obj1.calculaPares ); Thread t2= new Thread( obj1.calculaImpares ); t1.Start(); t2.Start(); } } }

Apndice E Cdigo ejemplo, realizando en forma paralela. Utiliza hilos. Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000 . El punto de entrada al hilo es un mtodo de instancia que es privado, pero an as compila el cdigo y lo ejecuta correctamente.Recibe como parmetro un objecto de la clase object.

using System; using System.Threading; namespace codigosEjemplo { public class ejemplo1 { //public void calculaPares() private void calculaPares(object nombre) { int cont=0; System.Console.WriteLine("iniciando: {0}", nombre ); for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0} ", cont); } //public void calculaImpares() private void calculaImpares(object nombre) { int cont=0; System.Console.WriteLine("iniciando: {0}", nombre ); for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("impares {0} ", cont); } public static void Main() { ejemplo1 obj1= new ejemplo1(); System.Console.WriteLine("pares hasta el 500,000"); Thread t1= new Thread( obj1.calculaPares ); Thread t2= new Thread( obj1.calculaImpares ); t1.Start("pares"); t2.Start("impares"); } } }

Apndice F Cdigo ejemplo, realizando en forma paralela. Utiliza hilos. Calcula la cantidad de nmeros pares e impares desde el 1 hasta el 500,000 . El punto de entrada a uno de los hilos es un mtodo de instancia que es privado y para el otro hilo es pblico.Recibe como parmetro un objecto de la clase object que proviene de una clase que unicamente sirve para transportar parmetros. Esta clase pudo tener ms propiedades.

using System; using System.Threading; namespace codigosEjemplo { public class mensaje

{ String msg_; public mensaje(String valor) { msg_= valor; } public String msg { get { return msg_; } set { msg_= value; } } } public class ejemplo1 { public void calculaPares(object nombre) { int cont=0; System.Console.WriteLine("iniciando: {0}", ((mensaje) nombre).msg ); for(int i=1; i<=500000; cont+=(i%2 ==0?1:0), i+=1 ); System.Console.WriteLine("pares {0} ", cont); } //public void calculaImpares() private void calculaImpares(object nombre) { int cont=0; System.Console.WriteLine("iniciando: {0}", ((mensaje) nombre).msg ); for(int i=1; i<=500000; cont+=(i%2==1?1:0), i+=1 ); System.Console.WriteLine("impares {0} ", cont); } public static void Main() { ejemplo1 obj1= new ejemplo1(); mensaje objMsg1= new mensaje("pares"); mensaje objMsg2= new mensaje("impares"); System.Console.WriteLine("pares hasta el 500,000"); Thread t1= new Thread( obj1.calculaPares ); Thread t2= new Thread( obj1.calculaImpares ); t1.Start( objMsg1 ); t2.Start( objMsg2 ); } } }