InicioHazlo Tu MismoHilos y multitareas C#

Hilos y multitareas C#

Hazlo Tu Mismo2/22/2012


Hola a todos. Hoy vamos a tratar un tema referente al desarrollo de software. Es algo con lo que muchos se vuelven locos y algo que muchos otros piensan que es complicadísimo de entender e implementar, y peor aun, existen “programadores” que hasta creen que es algo innecesario.
Estoy hablando nada mas y nada menos que de “Threading” o (en criollo) “Hilos”.
La implementación de hilos en nuestras aplicaciones, mejorarán el rendimiento y la organización a bajo nivel de las mismas.
Un Hilo, no es mas que un Sub Proceso. Por tanto, delegar un procedimiento o una función a un hilo, no es mas que hacerla correr como un Sub Proceso del Proceso principal, que generalmente es el main de la aplicación.
La ventaja principal de trabajar de esta manera, es poder tener “Cosas” corriendo en BackGround. Esto es, tener por ejemplo un procedimiento corriendo, y poder seguir usando el programa principal de forma normal. Esto último lo van a entender bien cuando hagamos la práctica.
Dada esta introducción adentrémonos en el tema.
El lenguaje elegido esta vez es C#.net porque me parece que ya es hora de aprender un lenguaje complejo (dije complejo, no difícil) y altamente funcional.
Vamos a hacer una aplicación que cree por código múltiples barras de progreso y las valla llenando según lo indique una función.
Abrimos el Visual Studio y creamos un nuevo proyecto C# Aplicación de Windows.
En el formulario que se nos crea por defecto solo agregamos un botón en una esquina y ajustamos el tamaño de esta manera:




namespace EjemploHilos1
{
public partial class Form1 : Form
{
int Posicion = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Posicion = Posicion + 30;
CrearProgressBars(23, Posicion, 23, 200);
}
private void CrearProgressBars(int sX, int sY, int sAltura, int sAncho)
{
ProgressBar pb = new ProgressBar();
int ContarHasta = new Random().Next(100000, 5000000);
pb.SetBounds(sX, sY, sAncho, sAltura);
pb.Parent = this;
pb.CreateControl();
for (int contador = 1; contador <= 100; contador++)
{
pb.Value = contador;
for (int CuentaNumeros = 0; CuentaNumeros <= ContarHasta; CuentaNumeros++) ;
}
}
}
}


Veamos la explicación:
Primero declaramos la variable Posicion y la inicializamos en cero. Esta variable se encargará de llevar la coordenada de altura que tendrá la nueva barra de progreso. Sin esta variable, todas las barras se crearían una arriba de la otra.


public Form1()
{
InitializeComponent();
}
Estas líneas son propias de Visual Studio y se encargan de inicializar todos los componentes del formulario.
{
Posicion = Posicion + 30;
CrearProgressBars(23,Posicion,23,200);
}

Acá veremos el evento Click del botón. Acá hacemos que la variable global Posicion se incremente en 30. Las barras de progreso las crearemos con una altura de 23 unidades, por eso la nueva posición va a ser 30 unidades por debajo de la anterior barra (23 que ocupa la barra anterior y 7 de separación así no quedan pegaditas ^_^ ). Después llamamos a la función CrearProgressBars() y le pasamos por valor las coordenadas de posicionamiento en el form mas el ancho y el alto.

private void CrearProgressBars(int sX, int sY, int sAltura, int sAncho)
{
ProgressBar pb = new ProgressBar();
int ContarHasta = new Random().Next(100000, 5000000);
pb.SetBounds(sX, sY, sAncho, sAltura);
pb.Parent = this;
pb.CreateControl();
for (int contador=1; contador <= 100; contador++)
{
pb.Value = contador;
for (int CuentaNumeros = 0; CuentaNumeros <= ContarHasta ; CuentaNumeros++) ;
}
}


Esta es nuestra función encargada de crear las barras. La función recibe los parámetros sX (coordenada X), sY (coordenadaY), sAltura y sAncho, todos de tipo entero.
Primero y principal declaramos e instanciamos pb de modo que nos quede un nuevo objeto de tipo ProgressBar. Luego utilizamos la propiedad SetBounds para establecer el posicionamiento en el formulario y le pasamos los parámetros de posicionamiento recibidos.
También declaramos la variable ContarHasta de tipo entero y le asignamos un número al azar entre cien mil y cinco millones.
Ahora le decimos a la propiedad Parent que el contenedor padre del control es este mismo formulario (pb.Parent = this, y por último llamamos al método CreateControl() para que al fin nos cree el control en el formulario.
Lo siguiente es generar el retardo suficiente para llenar la barra de progreso. Hay muchas formas de hacer esto. Yo elegí hacer que el programa cuente de 0 hasta un número aleatorio alto (como mínimo 100 mil y como máximo 5 millones en mi caso), acción que según la capacidad de procesamiento de mi pobre computadora, es suficiente para que el proceso sea visible al ojo humano ejeje. Si ustedes tienen computadoras mas rápidas, aumenten esta cantidad hasta que se ajuste a sus requerimientos.
Para esto hice dos bucles For. el primero declara una variable contador de tipo entero, la inicializa en uno y se va a repetir hasta que la variable llegue a 100 incrementándola de uno en uno. En cada repetición aumenta el valor de la propiedad Value de la barra, (que por defecto es cero) en 1, (Esto es lo que hará que vallan pasando las rayitas en la barra ^_^). El segundo bucle For es el que hace el trabajo sucio. Declara la variable CuentaNumeros de tipo entero, la inicializa en cero y se va a repetir hasta que la variable llegue al valor aleatorio que tomó la variable ContarHasta al principio de la función.
Bien, es hora de ejecutar el programa y ver los flamantes resultados. Ejecutemos y presionemos varias veces sobre el botón para ver que pasa.



Y???, ¿cómo les fue? Chan Chan!. La aplicación funciona, pero de una manera “poco ética” diría Richard Stallman. Si se fijaron bien, por mas que ustedes hacían repetidos clics sobre el botón, la aplicación estaba como trabada, y solo creaba la nueva barra una vez que la anterior terminaba de llenarse y no instantáneamente cuando ustedes hacían el clic. Si no te diste cuenta, ejecutá de nuevo el programa y volvé a probar.
Esto sucede porque todo corre en un solo proceso: el del programa en si. Por tanto, el proceso está activo, pero trabajando. Es por eso que perdemos el control de la aplicación. solo cuando la función CreateProgressBars() finaliza, el programa retorna el control al usuario.
Este mismo escenario, trasladado al desarrollo real se suele ver muy frecuentemente en aplicaciones que utilizan sockets o que realizan grandes transacciones a servidores de bases de datos en donde los tiempos de red no son siempre los que uno quisiera. La mayoría de estos casos a gran escala suelen terminar en un cuelgue generalizado de la aplicación y la perdida de información que esto conlleva.
Para evitar todos estos dolores de cabeza es que se usan los Hilos. Y como dijo un buen amigo, “El buen manejo de hilos es lo que separa a un Programador de un Aprendiz de coder”.
Quiero aclarar que esto de los hilos no es nada nuevo, ni tampoco es nada que Microsoft descubrió y que va a salvar al mundo ni nada de eso. La gente que programa en C o algunos de C++, vienen oyendo palabras como Hilos, sub procesos, delegados, etc desde hace mucho tiempo.
Lo novedoso, si se quiere, son las clases que el framework.net ofrece para el manejo de hilos, invokes y delegados. Están muy pulidas y constan de una gran abstracción, lo que facilita mucho el trabajo y el entendimiento de los mismos.
Todas las clases y SubClases referentes a hilos se encuentran en el espacio de nombres System.Threading, por lo tanto debemos importarlo al principio del código.
using System.Threading;
El FrameWork, también maneja los procesos y subProcesos de una forma especial, y no como simples procesos del sistema. Digo especial porque constan de restricciones de seguridad para evitar un mal uso de la sintaxis como sería puntear algo fuera de la memoria reservada del framework o acceder a un objeto situado en un proceso diferente. Pero bueno mejor no sigo que no quiero que se mareen. Sigamos. Lo único que me interesa que sepan es que para el FrameWork, los procesos “Desprendidos” del proceso principal son SubProcesos del mismo, (y no procesos independientes), y el sistema está enterado de esto. Cuando el proceso principal muera, morirán también todos sus SubProcesos, por mas que se encuentren en el medio de la ejecución. Y si queda algo en memoria, ya se encargará el GarbageCollector. Ahora si, sigamos ejeje.
Ustedes me van a putear, pero después de pensarlo mucho decidí no usar el código antes visto para seguir explicando el uso de hilos, ya que decidí no meterme en temas muy profundos como son los delegados, los handlers y los eventos porque ya se perdería el enfoque de este tutorial. Mejor vamos a hacer un código nuevo y ver bien gráficamente el trabajo con hilos. Mejor usemos el código anterior para ver lo que sucede con un programa normal cuando ejecutamos múltiples acciones sobre el mismo proceso (se cuelga).
Lo que sucede es lo siguiente. Las barras de progreso son creadas desde el proceso principal, pero para ir llenándose necesitan ser accedidas desde el hilo que se encargue de esa tarea. Ahora el problema está en que a partir del framework 3.0 un objeto solo puede ser accedido solo desde el mismo proceso que lo creó. Por tanto habría que crear un delegado que obtenga los datos del estado de la barra, se los pase a un handler y este los traiga a una función dentro del proceso principal que se encargue de actualizar la barra. No es que sea algo del otro mundo, pero si es algo demasiado avanzado para este tutorial, pero lo dejo pendiente para los próximos!!!
Datos archivados del Taringa! original
10puntos
0visitas
0comentarios
Actividad nueva en Posteamelo
0puntos
1visitas
0comentarios
Dar puntos:

Dejá tu comentario

0/2000

Autor del Post

r
rolignu2🇦🇷
Usuario
Puntos0
Posts26
Ver perfil →
PosteameloArchivo Histórico de Taringa! (2004-2017). Preservando la inteligencia colectiva de la internet hispanohablante.

CONTACTO

18 de Septiembre 455, Casilla 52

Chillán, Región de Ñuble, Chile

Solo correo postal

© 2026 Posteamelo.com. No afiliado con Taringa! ni sus sucesores.

Contenido preservado con fines históricos y culturales.