Professional Documents
Culture Documents
Len, Nicaragua
Programacin Visual I
Ingeniera en Telemtica
Contenidos
Introduccin
El hilo principal
Ejemplo de una aplicacin sin hilo
El espacio de nombre System.Threading
La clase Thread
Mtodos de la clase Thread
Propiedades de un hilo
Estados de un hilo
Ejemplo de aplicacin con hilo
Delegados
Acceso a controles empleando Delegados
Componente BackgroundWorker
Mecanismos de sincronizacin
Exclusin mutua
Detener un hilo de forma controlada
Bibliografa
Programacin Visual I
Ingeniera en Telemtica
Introduccin
Las aplicaciones que constan de un nico hilo de ejecucin resultan ms faciles de
implementar y depurar. No pasa lo mismo con las aplicaciones que tiene muchos hilos de
ejecucin las que comparten entre otros recursos la misma zona de memoria.
El diseo correcto de una aplicacin concurrente permite completar una mayor cantidad de
trabajo en el mismo periodo de tiempo.
El objetivo principal de las aplicaciones que implementan hilos, es aumentar el rendimiento
del sistema.
En Windows, cada ventana y cada control pueden responder a un conjunto de eventos
predefinidos. Cuando ocurre uno de estos eventos, Windows lo transforma en un mensaje
que coloca en la cola de mensajes de la aplicacin implicada.
Programacin Visual I
Ingeniera en Telemtica
El hilo principal
Cuando se ejecuta una aplicacin se lanza un hilo principal que se encargar de procesar la
secuencia de eventos que recibe la aplicacin. El hilo principal es el encargado de extraer
los mensajes de la cola y de procesarlos. Evidentemente cada mensaje almacenar la
informacin suficiente para identificar al objeto y ejecutar de forma sincrona el mtodo que
tiene para resoibder a ese evento:
Donde se posee una etiqueta llamada etHota la cual se actualiza cada segundo. Un botn
(btCalcular) que inicia la operacin a realizar por la aplicacin, la cual consiste en un ciclo
que realiza la cantidad de iteraciones indicadas en el control NumericUpDown
(numCargaUCP) y una barra de progreso (pbProgreso) que mostrar el avance de la
operacin.
Programacin Visual I
Ingeniera en Telemtica
btCalcular.Enabled = true;
numCargaUCP.Enabled = true;
}
}
Programacin Visual I
Ingeniera en Telemtica
Programacin Visual I
Ingeniera en Telemtica
Mutex
Monitor
Interlocked
AutoResetEvent
Pool (Permite usar un grupo de hilos)
Timer (Clase que ejecuta mtodos de devolucin de llamadas en hilos del grupo de
hilos)
Programacin Visual I
Ingeniera en Telemtica
La clase Thread
Un proceso es un programa en ejecucin. Al crear un proceso el sistema operativo
introduce un hilo (hilo principal) para ejecutar el cdigo. A partir de ese punto pueden
crearse y destruirse otros hilos en el dominio de la aplicacin
Un hilo, tambin llamado subproceso, es un objeto de la clase Thread, cuyo constructor
acepta un nico parmetro un delegado ThreadStart que contiene una referencia al
mtodo que se invocar mediante objeto Thread cuando llame a su mtodo Start del. Si se
llama a Star ms de una vez, se lanzar una excepcin ThreadStateException.
Nuestra aplicacin necesitara poseer un hilo secundario para evitar que se quede
congelada producto de la operacin intensa que realiza:
Hilo
secundario
Programacin Visual I
Ingeniera en Telemtica
Descripcin
Start
Sleep
Suspend
Abort
Resume
Join
Deja en espera un hilo hasta que finalice un hilo difente. Si se utiliza con un valor de
tiempo de espera, devuelve true si el hilo finaliza en el tiempo asignado
Programacin Visual I
Ingeniera en Telemtica
10
Propiedades de un hilo
Propiedad
Descripcin
IsAlive
IsBackGround
Permite obtener o establecer un bool (por defecto vale false), que indica si el
hilo es o debera de ser un hilo en segundo plano. Un hilo en segundo plano
funciona casi igual que un hilo en primer plano, exepto que no permite que
finalice un proceso. SI un proceso en primer plano finaliza, este llama al
mtodo Abort de los hilos en segundo plano activos.
Name
Priority
ThreadState
Programacin Visual I
Ingeniera en Telemtica
11
Estados de un hilo
Cuando un hilo es creado, pasa al estado Unstarted. Estado que mantiene hasta que se
llama al mtodo Start, a continuacin se muestran acciones que pueden provocar un
cambio de estado en el hilo.
Accin
Estado resultante
No cambia
Rinning
WaitSleepJoin
WaitSleepJoin
WaitSleepJoin
SuspendRequested
Suspended
Running
Running
AbortRequested
Aborted
Programacin Visual I
Ingeniera en Telemtica
12
Programacin Visual I
Ingeniera en Telemtica
13
Esta excepcin ocurre porque los controles de los formularios Windows solo pueden ser accedidos por
el hilo que los cre. No son seguros para la ejecucin de hilos porque si se tuviesen dos o ms hilos
manipulando el estado del control, es posible generar inconsistencias, condiciones de carrera o
interbloqueos. Por eso es importante que el acceso a los controles del formulario se haga de manera
segura para lo cual hay dos formas:
1. Utilizando delegados para habilitar llamadas asincronas para cada propiedad de cada control que
tenga que ser accedido de manera segura desde un hilo.
2. Utilizando un componente BackgroundWorker
Programacin Visual I
Ingeniera en Telemtica
14
Delegados
Un delegado es una clase que puede contener una referencia a un mtodo. nicamente
pueden guardar referencias a los mtodos que coinciden con su prototipo. Por ello
Tenemos dos formas de llamar a un mtodo que tiene que acceder a un control:
1. Sincrona Invoke: el hilo actual queda bloqueado hasta que el y el mtodo
referenciado por el delegado finalice su ejecucin.
2. Asincrona BeginInvoke: Una vez efectuada la llamada al mtodo, se retorna al hilo
actual para continuar su ejecucin.
En nuestro ejemplo, el mtodo TareaSecundaria que se ejecuta como hilo realiza 3 accesos
a controles del formulario principal que debern hacerse empleando delegados:
pbProgreso.Value = tpHecho;
btCalcular.Enabled = true;
numCargaUCP.Enabled = true;
Programacin Visual I
Ingeniera en Telemtica
15
Por lo tanto la declaracin del delegado a emplear debe retornar void y recibir un entero
como parmetro:
private delegate void SetValueDelegate(int prValue);
16
//Se llamar a Invoke lo cual ejecutar el mtodo apuntado por el delegado pasndole los
//parmetros en un arreglo de object. Esto provocar que se llama nuevamente al mtodo
// actual pero como si fuera el hilo principal con lo que ya no entrar en el if sino en el else
pbProgreso.Invoke(delegado, new object[] { hecho });
}
else
//Se establece el valor a la barra de progreso
pbProgreso.Value = hecho;
}
Programacin Visual I
Ingeniera en Telemtica
17
Un delegado tambin puede ser un objeto MethodInvoker. Una llamada a un objeto de este
tipo ser ms rpida que una llamada a otro tipo de delegados (como delegate o
EventHandler). La nica restriccin es que este mtodo no permite emplear parmetros.
En nuestro caso ser til para el acceso a btCalcular y numCargaUCP ya que en ambos casos
lo que se desea hacer es poner su propiedad Enabled a true.
Programacin Visual I
Ingeniera en Telemtica
18
19
20
Componente BackgroundWorker
BackgroundWorker, es una forma de garantizar que una aplicacin sea sensible a las
acciones del usuario. Este componente se encuentra en el espacio de nombre
System.ComponentModel y esta disponible en panel de componentes de la caja de
herramientas.
Programacin Visual I
Ingeniera en Telemtica
21
Componente BackgroundWorker
Para emplear este componente lo primero que debemos realizar es agregar un control del
tipo BackgroundWorker desde la barra de herramientas. En nuestro caso lo llamaremos
hiloTrabajador
Ahora dentro del evento clic del botn btCalcular llamamos al mtodo RunWorkerAsync del
control hiloTrabajador:
private void btCalcular_Click(object sender, EventArgs e)
{
btCalcular.Enabled = false;
numCargaUCP.Enabled = false;
pbProgreso.Value = 0;
/* Inicia el hilo secundario encapsulado por el objeto BackgroundWorker */
hiloTrabajador.RunWorkerAsync();
}
Esto provocar que se ejecute el mtodo asociado al evento DoWork del hiloTrabajador.
Programacin Visual I
Ingeniera en Telemtica
22
Componente BackgroundWorker
El evento DoWork tiene como parmetro un objeto de la clase DoWorkEventArgs que tiene
dos propiedades: Argument y Result. La primera contendr el valor del parmetro de tipo
object que opcionalmente se puede especificar cuando se invoca al mtodo
RunWorkerAsync, y la segunda se utiliza para asignar el resultado final de la operacin el
cual debera ser recuperado cuando el evento RunWorkerCompleted sea controlado:
/* Metodo que se ejecuta al llamar al mtodo RunWorkerAsync del objeto BackgroundWorker */
private void hiloTrabajador_DoWork(object sender, DoWorkEventArgs e)
{
/* Aunque podriamos colocar aqui el cdigo q tenemos en Tarea secundaria, no lo hacemos
* por si tenemos varios BackgroundWorker que tengan asociado el mismo mtodo al llamar a
* RunWorkerAsync. De esta manera al obtener primero la referencia podramos por ejemplo
* diferenciar entre los diferentes BackgroundWorker antes de ejecutar el cdigo correspondiente
* */
BackgroundWorker hiloTr = (BackgroundWorker)sender;
/* En nuestro caso esta comparacin esta dems por que solo tenemos un BackgroundWorker pero
* se deja para ejemplificar como se llevara a cabo la comprobacin */
if(hiloTr == hiloTrabajador)
TareaSecundaria(hiloTr, e);
}
Programacin Visual I
Ingeniera en Telemtica
23
Componente BackgroundWorker
Cuando llamamos a TareaSecundaria necesitamos pasar la referencia al componente
BackgroundWorker as como los datos del evento (e) para desde el mismo poder facilitar
informacin sobre el progreso de la tarea y su posible cancelacin:
private void TareaSecundaria(BackgroundWorker hiloTr, DoWorkEventArgs e)
{
int hecho = 0, tpHecho = 0;
while (hecho < numCargaUCP.Value)
{
hecho += 1;
tpHecho = (int)(hecho / numCargaUCP.Value * 100);
if (tpHecho > pbProgreso.Value)
{
/* Llamada al mtodo ReportProgress del BackgroundWorker lo que genera el evento ProgressChanged */
hiloTr.ReportProgress(tpHecho);
}
/*Se consulta si se ha solicitado la cancelacin de la tarea por parte del hilo principal*/
if (hiloTr.CancellationPending)
{
/* Aunque no es necesaria colocar Cancel a true para que la cancelacin ocurra esto permite diferenciar desde el
* mtodo RunWorkerCompleted cual fue la razn de la terminacin del hilo */
e.Cancel = true;
break;
}
}
}
24
Ingeniera en Telemtica
Componente BackgroundWorker
Para dar notificacin sobre el progreso de una tarea realizada por un BackgroundWorker
debemos:
1. Establecer la propiedad WorkerReportsProgress a true (desde la ventana de
propiedades).
2. Aadir un controlador al mtodo ProgressChanged el cual es invocado al ejecutarse la
lnea hiloTr.ReportProgress(tpHecho).
private void hiloTrabajador_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbProgreso.Value = e.ProgressPercentage;
}
25
Componente BackgroundWorker
El evento RunWorkerCompleted es generado en tres circunstancias diferentes: cuando
finaliza una tarea en segundo plano, cuando es cancelada, o cuando se lanza una
excepcin:
private void hiloTrabajador_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
/* Consulta si se produjo un error */
if (e.Error != null)
MessageBox.Show(e.Error.Message);
/* Consulta si la terminacin se llevo a cabo porque la operacin fue cancelada */
else if (e.Cancelled)
MessageBox.Show("Operacin cancelada");
/* Si no es un error o una cancelacin, la tarea termino correctamente */
else {
btCalcular.Enabled = true;
numCargaUCP.Enabled = true;
}
}
Como se puede observarse, el argumento e tiene las propiedades Error, Cancel, y Result, las
cuales son utilizadas para obtener el estado de la operacin y su resultado final.
Programacin Visual I
Ingeniera en Telemtica
26
Componente BackgroundWorker
Para cancelar la tarea en segundo plano debemos poner la propiedad WorkerSupportsCancellation del
BackgroundWorker a true e invocar el mtodo CancelAsync del componente.
En el siguiente ejemplo realizamos la solicitud de la cancelacin desde el mtodo FormClosing del
formulario:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
/** Indicamos que deseamos cancelar la ejecucin del hilo secundario **/
hiloTrabajador.CancelAsync();
}
Cuando esto se cumple, se asigna a la propiedad Cancel de DoWorkEventArgs el valor true que
posteriormente es reconocido en el mtodo RunWorkerCompleted.
Programacin Visual I
Ingeniera en Telemtica
27
Mecanismos de sincronizacin
Cuando en una aplicacin se ejecuta varios hilos concurrentemente, en muchos casos ser
necesario emplear mecanismos de sincronizacin para que estos coordinen su ejecucin.
La infraestructura de la mquina virtual de .NET, ofrece diversas estrategias para sincronizar
el acceso a objetos y miembros estticos dentro de las cuales se encuentran los objetos de
sincronizacin que permiten realizar una sincronizacin manual.
Objetos de sincronizacin
Sirven para controlar la interaccin entre los hilos y evitar condiciones de carrera y otras
anomalas que se puedan producir. Estos pueden dividirse en 3 categoras: exclusin mutua,
sealizacin e interbloqueo. No obstante algunos mecanismos de sincronizacin pueden
emplearse en ms de una categora.
Programacin Visual I
Ingeniera en Telemtica
28
Exclusin mutua
Garantiza que la seccin crtica ser ejecutada solo por un hilo cada vez y se puede
implementar utilizando cerrojos (lock) o monitores (Monitor).
Lock: Un hilo que acceda a la seccin crtica cuando el cerrojo est echado porque la esta
ejecutando otro hilo, se bloquea hasta que el cerrojo sea liberado.
lock(iteraciones)
{
iteraciones++;
}
Programacin Visual I
Ingeniera en Telemtica
29
Exclusin mutua
try {
Monitor.Enter(iteraciones);
iteraciones++;
Monitor.Exit(iteraciones);
}
catch(Exception ex) {
Debug.WriteLine(ex.Message);
}
finally {
Monitor.Exit(iteraciones);
}
Donde el mtodo Enter de Monitor marca el principio de una seccin crtica y ningn otro
hilo puede entrar a la seccin crtica, hasta que sea liberado el recurso bloqueado mientras
que el mtodo Exit libera el bloqueo sobre un recurso a la vez que marca el final de una
seccin crtica protegida por el recurso bloqueado.
Programacin Visual I
Ingeniera en Telemtica
30
31
Bibliografa
Programacin Visual I
Ingeniera en Telemtica
32