Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Un hilo es bsicamente una tarea que puede ser ejecutada en paralelo con otra
tarea.
Los hilos de ejecucin que comparten los mismos recursos, sumados a estos recursos,
son en conjunto conocidos como un proceso. El hecho de que los hilos de ejecucin de
un mismo proceso compartan los recursos hace que cualquiera de estos hilos pueda
modificar stos. Cuando un hilo modifica un dato en la memoria, los otros hilos acceden
a ese dato modificado inmediatamente.
El proceso sigue en ejecucin mientras al menos uno de sus hilos de ejecucin siga
activo. Cuando el proceso finaliza, todos sus hilos de ejecucin tambin han terminado.
Asimismo en el momento en el que todos los hilos de ejecucin finalizan, el proceso no
existe ms y todos sus recursos son liberados.
1
Fuente de consulta secundaria. http://es.wikipedia.org/wiki/Hilo_de_ejecuci%C3%B3n
Delphi2). Otros programas por no decir que la mayora desconocen la existencia de hilos
de ejecucin y stos deben ser creados mediante llamadas de biblioteca especiales que
dependen del sistema operativo en el que estos lenguajes estn siendo utilizados (como
es el caso del C y del C++).
Los hilos no pueden ejecutarse ellos solos; requieren la supervisin de un proceso padre
para correr.
Dentro de cada proceso hay varios hilos ejecutndose. Por ejemplo, Word puede tener
un hilo en background chequeando automticamente la gramtica de lo que se est
escribiendo, mientras otro hilo puede estar salvando automticamente los cambios del
documento en el que se trabaja.
Como Word, cada aplicacin (proceso) puede correr varios hilos los cuales estn
realizando diferentes tareas. Esto significa que los hilos estn siempre asociados con un
proceso en particular.
Los hilos a menudo son conocidos o llamados procesos ligeros. Un hilo, en efecto, es
muy similar a un proceso pero con la diferencia de que un hilo siempre corre dentro del
contexto de otro programa. Por el contrario, los procesos mantienen su propio espacio
de direcciones y entorno de operaciones.
2
Es un entorno de desarrollo de software diseado para la programacin de propsito general con nfasis
en la programacin visual. En Delphi se utiliza como lenguaje de programacin una versin moderna de
Pascal llamada Object Pascal. En sus diferentes variantes, permite producir archivos ejecutables para
Windows, GNU/Linux y la plataforma .NET.
Delphi inicialmente slo produca ejecutables binarios para Windows: Delphi 1 para Win16 y con Delphi
2 se introdujo Win32. En la actualidad da ms posibilidades, como son:
Existe una versin de Delphi para sistemas Unix y Linux, denominada Kylix (de la cual existe una
versin gratuita, aunque limitada). Sin embargo Kylix fue congelado por Borland en su versin 3.00.
Los hilos dependen de un programa padre en lo que se refiere a recursos de ejecucin.
La siguiente figura muestra le relacin entre hilos y procesos.
Aqu, cuando se llama a main(), la aplicacin imprime el mensaje y termina. Esto ocurre
dentro de un nico thread.
La clase Thread
Mtodos de Clase
Estos son los mtodos estticos que deben llamarse de manera directa en la clase
Thread.
currentThread()
Este mtodo devuelve el objeto thread que representa al hilo de ejecucin que se est
ejecutando actualmente.
yield()
Este mtodo hace que el intrprete cambie de contexto entre el hilo actual y el siguiente
hilo ejecutable disponible. Es una manera de asegurar que nos hilos de menor prioridad
no sufran inanicin.
sleep( long )
El mtodo sleep() provoca que el intrprete ponga al hilo en curso a dormir durante el
nmero de milisegundos que se indiquen en el parmetro de invocacin. Una vez
transcurridos esos milisegundos, dicho hilo volver a estar disponible para su ejecucin.
Los relojes asociados a la mayor parte de los intrpretes de Java no sern capaces de
obtener precisiones mayores de 10 milisegundos, por mucho que se permita indicar
hasta nanosegundos en la llamada alternativa a este mtodo.
Mtodos de Instancia
start()
Este mtodo indica al intrprete de Java que cree un contexto del hilo del sistema y
comience a ejecutarlo. A continuacin, el mtodo run() de este hilo ser invocado en el
nuevo contexto del hilo. Hay que tener precaucin de no llamar al mtodo start() ms de
una vez sobre un hilo determinado.
run()
stop()
suspend()
resume()
El mtodo resume() se utiliza para revivir un hilo suspendido. No hay garantas de que
el hilo comience a ejecutarse inmediatamente, ya que puede haber un hilo de mayor
prioridad en ejecucin actualmente, pero resume() ocasiona que el hilo vuelva a ser un
candidato a ser ejecutado.
setPriority( int )
El mtodo setPriority() asigna al hilo la prioridad indicada por el valor pasado como
parmetro. Hay bastantes constantes predefinidas para la prioridad, definidas en la clase
Thread, tales como MIN_PRIORITY, NORM_PRIORITY y MAX_PRIORITY, que
toman los valores 1, 5 y 10, respectivamente. Como gua aproximada de utilizacin, se
puede establecer que la mayor parte de los procesos a nivel de usuario deberan tomar
una prioridad en torno a NORM_PRIORITY. Las tareas en segundo plano, como una
entrada/salida a red o el nuevo dibujo de la pantalla, deberan tener una prioridad
cercana a MIN_PRIORITY. Con las tareas a las que se fije la mxima prioridad, en
torno a MAX_PRIORITY, hay que ser especialmente cuidadosos, porque si no se hacen
llamadas a sleep() o yield(), se puede provocar que el intrprete Java quede totalmente
fuera de control.
getPriority()
Este mtodo devuelve la prioridad del hilo de ejecucin en curso, que es un valor
comprendido entre uno y diez.
setName( String )
Este mtodo permite identificar al hilo con un nombre menmnico. De esta manera se
facilita la depuracin de programas multihilo. El nombre mnemnico aparecer en todas
las lneas de trazado que se muestran cada vez que el intrprete Java imprime
excepciones no capturadas.
getName()
Este mtodo devuelve el valor actual, de tipo cadena, asignado como nombre al hilo en
ejecucin mediante setName().
Diferencias entre hilos y procesos
Al igual que los procesos, los hilos poseen un estado de ejecucin y pueden
sincronizarse entre ellos para evitar problemas de compartimiento de recursos.
Generalmente, cada hilo tiene una tarea especfica y determinada, como forma de
aumentar la eficiencia del uso del procesador.
Estados de un hilo
Los principales estados de los hilos son: Ejecucin, Listo y Bloqueado. No tiene
sentido asociar estados de suspensin de hilos ya que es un concepto de proceso. En
todo caso, si un proceso est expulsado de la memoria principal (RAM), todos sus hilos
debern estarlo ya que todos comparten el espacio de direcciones del proceso.
Cambio de estados
Creacin: Cuando se crea un proceso se crea un hilo para ese proceso. Luego,
este hilo puede crear otros hilos dentro del mismo proceso, proporcionando un
puntero de instruccin y los argumentos del nuevo hilo. El hilo tendr su propio
contexto y su propio espacio de la columna, y pasara a la final de los listos.
3
Parte de un programa encargada de lanzar un proceso en el servidor de un entorno cliente/servidor.
Terminacin: Cuando un hilo finaliza se liberan tanto su contexto como sus
columnas.
Los hilos son generados a partir de la creacin de un proceso, por ende, un proceso es
un hilo de ejecucin o Monohilo. Las ventajas de los hilos se dan en los Multihilos, que
es cuando un proceso tiene mltiples hilos de ejecucin los cuales realizan actividades
distintas, que pueden o no ser cooperativas entre s. Los beneficios de los hilos se
derivan de las implicaciones de rendimiento, as:
4
Es un registro especial donde el SO agrupa toda la informacin que necesita conocer respecto a un
proceso particular. Cada vez que se crea un proceso el SO crea el BCP correspondiente para que sirva
como descripcin en tiempo de ejecucin durante toda la vida del proceso.
Cuando el proceso termina, su BCP es borrado y el registro puede ser utilizado para otros procesos. Un
proceso resulta conocido para el SO y por tanto elegible para competir por los recursos del sistema slo
cuando existe un BCP activo asociado a l. El bloque de control de proceso es una estructura de datos con
campos para registrar los diferentes aspectos de la ejecucin del proceso y de la utilizacin de recursos.
La informacin almacenada en un BCP incluye tpicamente algunos o todos los campos siguientes:
Esta lista es simplemente indicativa, cada sistema operativo tiene su propio diseo de BCP, con el
conjunto de metadatos necesarios para la administracin. Puede medir desde 32 bits a 1024. Su
denominacin cambia segn el sistema operativo, por ej. en IBM se designa PSW por palabra de estado
de proceso. Difiere significativamente entre los sistemas de procesamiento por lotes (BATCH) y los
sistemas interactivos.
Una vez creado, el BCP se rellena con los atributos definidos como parmetros que se hallan en la
plantilla del proceso o que son especificados como parmetros de la llamada al SO crear_proceso. En ese
momento el sistema operativo suele asignar valores a otros campos. Por ejemplo, cuando se crea un
3. Se tarda mucho menos tiempo en cambiar entre dos hilos de un mismo proceso
4. Los hilos aumentan la eficiencia de la comunicacin entre programas en
ejecucin. En la mayora de los sistemas en la comunicacin entre procesos debe
intervenir el ncleo para ofrecer proteccin de los recursos y realizar la
comunicacin misma. En cambio, entre hilos pueden comunicarse entre s sin la
invocacin al ncleo. Por lo tanto, si hay una aplicacin que debe implementarse
como un conjunto de unidades de ejecucin relacionadas, es ms eficiente
hacerlo con una coleccin de hilos que con una coleccin de procesos separados.
Sincronizacin de hilos
Todos los hilos comparten el mismo espacio de direcciones y otros recursos como
pueden ser archivos abiertos. Cualquier
modificacin de un recurso desde un hilo afecta
al entorno del resto de los hilos del mismo
proceso. Por lo tanto, es necesario sincronizar la
actividad de los distintos hilos para que no
interfieran unos con otros o corrompan
estructuras de datos.
proceso, los registros e indicadores hardware se fijan a los valores proporcionados por el
cargador/enlazador. Cada vez que un proceso queda suspendido, el contenido de los registros del
procesador es generalmente guardado en la pila, y el puntero al marco de la pila en cuestin se almacena
en el BCP. De este modo los valores de los registros son restaurados cuando el proceso es seleccionado
para ejecutarse nuevamente.
5
Un semforo es una variable especial (o tipo abstracto de datos) que constituye el mtodo clsico para
restringir o permitir el acceso a recursos compartidos (por ejemplo, un recurso de almacenamiento del
sistema o variables del cdigo fuente) en un entorno de multiprocesamiento (en el que se ejecutarn
varios procesos concurrentemente). Los semforos pueden ser usados para diferentes propsitos, entre
ellos:
Usos ms comunes
Por ejemplo, en un programa de hoja de clculo un hilo puede estar visualizando los
mens y leer la entrada del usuario mientras que otro hilo ejecuta las rdenes y actualiza
la hoja de clculo. Esta medida suele aumentar la velocidad que se percibe en la
aplicacin, permitiendo que el programa pida la orden siguiente antes de terminar la
anterior.
- Procesamiento asncrono
6
Es el bloqueo permanente de un conjunto de procesos o hilos de ejecucin en un sistema concurrente
que compiten por recursos del sistema o bien se comunican entre ellos. A diferencia de otros problemas
de concurrencia de procesos, no existe una solucin general para los interbloqueos.
- Aceleracin de la ejecucin
Se pueden ejecutar, por ejemplo, un lote mientras otro hilo lee el lote siguiente de un
dispositivo.
Implementaciones
En una aplicacin ULT pura, todo el trabajo de gestin de hilos lo realiza la aplicacin
y el ncleo o kernel no es consciente de la existencia de hilos. Es posible programar una
aplicacin como multihilo mediante una biblioteca de hilos. La misma contiene el
cdigo para crear y destruir hilos, intercambiar mensajes y datos entre hilos, para
planificar la ejecucin de hilos y para salvar y restaurar el contexto de los hilos.
En una aplicacin KLT pura, todo el trabajo de gestin de hilos lo realiza el kernel. En
el rea de la aplicacin no hay cdigo de gestin de hilos, nicamente un API (interfaz
de programas de aplicacin) para la gestin de hilos en el ncleo. Windows 2000, Linux
y OS/2 utilizan este mtodo. Linux utiliza un mtodo muy particular en el que no hace
diferencia entre procesos e hilos. Para Linux, si varios procesos creados con la llamada
al sistema "clone" comparten el mismo espacio de direcciones virtuales, el sistema
operativo los trata como hilos, y lgicamente son manejados por el kernel.
Mtodos
Ejemplos de multihilos
class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
class ExtendThread {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
Ejemplo 3.
Sea una clase que produce datos y otra que los visualiza. La productora de datos se
llama "tarea_datos" y la que los muestra se llama "tarea_vista". "tarea_vista" recibe una
referencia a "tarea_datos" para visualizar el resultado. Este ejemplo todava no contiene
hilos, su comprensin ayudar a entender como funcionan los hilos en los siguientes
ejemplos. Para acercarnos a lo que ser la explicacin sobre hilos, cada clase realiza su
labor en la funcin run(). "tarea_datos" lee un nmero de un archivo y la "tarea_vista"
lo muestra.
import java.io.*;
/****************************************
* Primera versin, sin hilos.
* En un slo hilo todo el procesamiento es secuencial y por tanto
* realiza la operacin correctamente, visualizando el dato
****************************************/
public class control01 {
public control01() {
tarea_datos01 t1 = new tarea_datos01();
tarea_vista01 t2 = new tarea_vista01( t1 );
t1.run(); // Lee dato
t2.run(); // Lo visualiza
}
public static void main(String[] args) { control01 control1 =
new control01(); }
}
void leer_datos() {
try {
BufferedReader in = new BufferedReader( new
FileReader("xxx") );
resultado = Double.parseDouble( in.readLine()
);
in.close();
}
catch (Exception e) { System.out.println(
e.getMessage() ); }
}
double obt_resultado() { return resultado; }
}
Entonces, tarea_vista es una clase excesivamente ligera o pequea, esto solo por
ejemplo.
Puesto que el orden es secuencial y hay un nico hilo (el hilo de ejecucin de la funcin
main()), el resultado ser el esperado: imprimir por pantalla el nmero ledo del archivo.
Subclases de Thread
Ahora el programa anterior se pondr en forma de multihilos, de tal forma que cada
tarea sea un hilo. Por qu usar hilos? Analice, por ejemplo, que puede interesar
simultanear la lectura de un fichero muy grande con otras tareas. Al fin y al cabo,
estamos acostumbrados a esta simultaneidad mientras se navega por la web, donde a un
tiempo puede estar descargando un fichero y abriendo una pgina.
Algunas reglas:
En este caso se simula una situacin tpica para usar hilos: se necesita un flujo de
control que produce los datos (por lectura y/o clculo) y otro que los consume
(visualizacin, etc.), pero no hay seguridad de que el consumo este sincronizado con la
produccin. Al aplicar un esquema de programacin multihilo vamos a enfrentarnos a
alguno de los retos de la programacin concurrente.
Entonces, los nico que se ha hecho es heredar de la clase Thread y aplicar la regla 2, es
decir, llamamos a start() y esta funcin, predefinida por Java, llama automticamente
a run():
import java.io.*;
/****************************************
* Primera versin con hilos, que muestra el resultado incorrecto (-
1).
* Ya que el hilo de visualizacin realiza su tarea antes de que
* el hilo de datos termine de leer los datos. Para simular una
'larga'
* lectura usamos sleep( milisegundos )
****************************************/
public class control02 {
public control02() {
tarea_datos02 t1 = new tarea_datos02();
tarea_vista02 t2 = new tarea_vista02( t1 );
t1.start(); // Lee dato
t2.start(); // Lo visualiza
}
public static void main(String[] args) { control02 control1 =
new control02(); }
}
void leer_datos() {
try {
BufferedReader in = new BufferedReader( new
FileReader("xxx") );
sleep( 1000 );
resultado = Double.parseDouble( in.readLine()
);
in.close();
}
catch (Exception e) { System.out.println(
e.getMessage() );}
}
Resultado: -1
Resulta evidente que se ha visualizado la variable antes de haber ledo su valor del
archivo. Necesitamos sincronizar los hilos. Necesitamos que el hilo de visualizacin no
se adelante al hilo de clculo.
Los mtodos sleep() e interrupt()
Esta es una primera aproximacin a la sincronizacin de hilos, usando sleep(), que sirve
para decirle a un hilo que se duerma durante un periodo de tiempo (medido en
milisegundos). En nuestro ejemplo modificamos tarea_datos() para que devuelva el
resultado ms tarde (y correctamente), es decir, retrasamos un hilo para "dar tiempo" a
otro para que termine su tarea:
double obt_resultado() {
try {
sleep(1050); // Duermo un poco
return resultado; // Devuelvo el dato
}
catch (InterruptedException e) {
System.out.println( e.getMessage() );
return -1;
}
}
Thread.sleep( 1050 );
if ( !isInterrupted() )
...
Los mtodos stop() y suspend() han sido desaconsejados por SUN.
Una buena metfora es pensar la situacin de bloqueo como una puerta que tiene un
cerrojo en su interior, cuando un hilo accede al mtodo cierra la puerta y bloquea la
puerta, de tal forma que otro hilo que quiera acceder a la misma se debe mantener en
espera hasta que el primero sale.
Para mantener un mtodo libre de problemas con los hilos (thread-safe), se utiliza la
palabra clave synchronized. El hilo anula el bloqueo cuando sale del ltimo mtodo
sincronizado. En nuestro caso hemos hecho que dos mtodos sean sincronizados:
Con wait() un hilo se queda en espera y libera el cerrojo sobre el objeto que hubiese
bloqueado (recuerde aqu la metfora de la puerta con cerrojo). Importante para evitar
esperas "eternas" (y aplicaciones "colgadas") es tener en cuenta que cuando un hilo
entra en espera no tiene posibilidad de despertarse slo, sino que depende de otro hilo
que lo despierte mediante notity(). Cuando no est seguro de cual es el hilo que debe
despertar lo ms seguro es usar notifyAll(). Las aplicaciones obedecen a una serie de
reglas:
Regla 2: cuando un hilo depende del estado de un objeto, debe esperar dentro del objeto
(no fuera), en un mtodo sincronizado en el que llama a wait(). Un esquema:
Regla 3: cuando un hilo cambia el estado de un objeto llama a notifyAll(), ya que de esta
forma da oportunidad a los dems para despertar y comprobar si el cambio les afecta.
Un esquema:
Regla 4: el mtodo run() suele tener la forma siguiente (ver Horstmann y Cornell ,2003,
p. 62-63):
Ver un buen ejemplo de wait() y notify() en Niemeyer y Knudsen (2000, pag. 257).
Ejemplo 4.
/*********************************************************************
**
Al presionar el botn Iniciar, se crea y arranca un hilo
Cada hilo mueve una bola
**********************************************************************
**/
public class animacion_bolas extends Applet {
int origen_x = 0;
private panel_bolas pbola = new panel_bolas();
private Panel pbotones = new Panel();
Button b_iniciar = new Button( "Iniciar"); // Boton para
iniciar una animacin
El panel de bolas lleva el registro (Vector) de las bolas creadas y pinta las bolas en
respuesta al evento paint:
Lo interesante es ver lo que ocurre cuando se ejecuta con start() el hilo: mueve cada
periodo de "milisegundos" la bola. Para determinar la velocidad usamos sleep().
Con sleep() no slo se consigue que duerma el hilo, sino que adems se tiene un hilo
bien diseado, ya que al dormir permite que otros hilos hagan su trabajo.
class bola {
private panel_bolas pbolas;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
private int x = 0;
private int y = 0;
private int dx = 2; // Salto en la X
private int dy = 2; // Salto en la Y
animacion_bolas_b_iniciar_actionAdapter(animacion_bolas
adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.b_iniciar_actionPerformed(e);
}
}
El interfaz Runnable
En ocasiones puede interesar que una clase que hereda de otra (por ejemplo de Applet)
al mismo tiempo contenga el mtodo run() propio de un Thread. Pero en Java, a
diferencia de C++, no hay herencia mltiple; en esta situacin una solucin tpica de
Java es combinar la herencia (extends) con la recepcin (implements) de un interfaz. En
nuestro ejemplo ocurre que la clase hereda (extends) de Applet y reciba un interfaz que
le permita contener el mtodo deseado, run(). Para ello usamos "implements Runnable".
En el siguiente ejemplo se tiene un applet que funciona como un reloj: cada segundo se
muestra por pantalla la hora:
/**************************************************************
**********
* run del hilo: se duerme durante un segundo
***************************************************************
********/
public void run() {
while ( hilo != null ) {
try {
Thread.sleep( periodo_refresco );
}
catch (InterruptedException e ) { return; }
repaint();
}
}
/**************************************************************
*********
* Parada del applet: si la referencia al hilo no es nula: paro
el hilo.
***************************************************************
********/
public void stop( ) {
if ( hilo != null ) {
hilo.interrupt();
hilo = null;
}
}
}
Aspectos de la solucin:
1. El hilo es un atributo del applet. Su variable sirve como seal de control: cuando
es null significa que el hilo est parado (adems facilita la recoleccin de
basura).
2. Con start() creamos el hilo (pasamos una referencia del applet, this, al
constructor del hilo). A continuacin iniciamos el hilo, por medio de la
llamada hilo.start(). No debemos confundir el mtodo start() del applet con el
mtodo start() del hilo.
3. El mtodo run() implementa la tarea que se desea: duerme durante un segundo y
llama a repaint().
4. Cuando el applet se detiene (stop), se interrumpe el hilo. Cuando se vuelva a
iniciar el applet (start) se vuelve a crear e iniciar el hilo.
Taller
1. Correr los ejemplos citados para comprobar su estructura.
2. Con base en sus conocimientos en programacin, desarrolle un programa
que aplique el concepto de threads, y relacinelo con lo visto hasta ahora
en clase. Este programa debe estar debidamente documentado, debe
manejar por lo menos dos hilos. Usted lo puede desarrollar en el lenguaje
que maneje.