13 julio 2006

Cómo crear un hilo de ejecución

Hay ocasiones en que necesitamos que nuestro programa realize paralelamente algún proceso secundario que no interfiera en la aplicación principal, ya que si nos metemos en bucles cerrados o procesos pesados (traspaso de ficheros, datos, etc.) nuestra aplicación se queda medio muerta (no se puede ni mover la ventana, minimizarla y menos cerrarla).

Para ello lo que hacemos es crear un hilo de ejecución heredando de la clase TThread del siguiente modo:

THilo = class( TThread )
  Ejecutar: procedure of object;
  procedure Execute; override;
end;


La definición anterior hay que colocarla dentro del apartado Type de nuestra unidad (en la sección interface). Le he añadido el procedimiento Ejecutar para poder mandarle que procedimiento queremos que se ejecute paralelamente.

En el apartado implementation de nuestra unidad redifinimos el procedimiento de la clase TThread para que llame a nuestro procedimiento Ejecutar:

procedure THilo.Execute;
begin
  Ejecutar;
  Terminate;
end;


Con esto ya tenemos nuestra clase THilo para crear todos los hilos de ejecución que nos de la gana. Ahora vamos a ver como se crea un hilo y se pone en marcha:

var
Hilo: THilo; // variable global o pública

procedure CrearHilo;
begin
  Hilo.Ejecutar := ProcesarDatos;
  Hilo.Priority := tpNormal;
  Hilo.Resume;
end;

procedure ProcesarDatos;
begin
  // Este es el procedimiento que ejecutará nuestro hilo
  // Cuidado con hacer procesos críticos aquí
  // El procesamiento paralelo de XP no es el de Linux
  // Se puede ir por las patas abajo...
end;


Si en cualquier momento queremos detener la ejecución del hilo:

Hilo.Terminate;
FreeAndNil( Hilo );


Los hilos de ejecución sólo conviene utilizarlos en procesos críticos e importantes. No es conveniente utilizarlos así como así ya que se pueden comer al procesador por los piés.

Pruebas realizadas en Delphi 7

19 comentarios:

Percy dijo...

Muy buenos los puntos que han tocado.
El hilo lo puedo utilizar para mandar qry, xq mi aplicación a veces que media muerta cuando mando alguna consulta y ésta demora en devolver la información.

Gracia, y sigue con éste Blogg

Administrador dijo...

Me alegro de que te haya sido útil. Yo suelo utilizar mucho los hilos en tareas pesadas y van de maravilla.

Un saludo.

Anónimo dijo...

Delphi al Límite
¿No podrias colocar otros ejemplos
donde uses hilos. de los que dices qeu te va de maravillas usar hilos?

Tu sitio es ameno e interesante. para
obtener informacion. en nuestro idioma

Administrador dijo...

Me alegro de que te guste este blog. Procuro que sea una información útil tanto para mi como para otros.

Cuando termine la serie que estoy dedicando a la programación de videojuegos voy a comenzar a escribir sobre Rad Studio 2007 y volveré al tema de los hilos en profundidad.

Saludos.

Anónimo dijo...

Muy buen ejemplo para empezar con los hilos en delphi, pero tengo problemas en la declaraciones, seria mucho pedir que pongas el codigo completo.

Gracias, excelente blog.

Anónimo dijo...

Muy bien explicado pero no he conseguido compilarlo.
Hilo.Ejecutar := ProcesarDatos Incompatible types(method pointer and regular procedure)

Administrador dijo...

Este artículo lo amplié más adelante en esta otra serie de artículos:

http://delphiallimite.blogspot.com/2009/05/los-hilos-de-ejecucion-1.html

Saludos.

Unknown dijo...

Tengo la siguiente duda, desde un hilo puedo acceder a los componentes que tengo en un form por ejemplo a un edit o un label, pero no se que estoy haciendo mal, que mi hilo no puedo acceder a los componentes!

Administrador dijo...

Eso se debe a que los componentes VCL se dibujan con el hilo principal de la aplicación, pero tu hilo es independiente y no está sincronizado con los componentes visuales.

Después de este artículo escribí estos otros hablando de los hilos de ejecución a fondo y como solucionar tu problema:

http://delphiallimite.blogspot.com/2009/05/los-hilos-de-ejecucion-1.html

Recibe un cordial saludo.

sikovi dijo...

Que tal un saludo es un super blog lo mejor que he visto.
mira no se si sea posible tengo que realizar un programa de un examen psicometrico para el colegio. pero no tengo mucha nocion de como empezar la cosa es que deve de tener opcion para colocar nombre elegir fichas de domino y al ultimo sacar el resultado para ver si es aprovado o no no se que funciones meter si me podrias ayudar muchichichisisisimas grax ... de antemano pasare el tip de tu blog es buenisimo...

sikovi dijo...

Que tal un saludo es un super blog lo mejor que he visto.
mira no se si sea posible tengo que realizar un programa de un examen psicometrico para el colegio. pero no tengo mucha nocion de como empezar la cosa es que deve de tener opcion para colocar nombre elegir fichas de domino y al ultimo sacar el resultado para ver si es aprovado o no no se que funciones meter si me podrias ayudar muchichichisisisimas grax ... de antemano pasare el tip de tu blog es buenisimo...

Administrador dijo...

Un programa de gestión, por muy pequeño de sea (al final nunca lo son), no es una cosa que se realice en dos tardes, y más si no tienes conocimientos profundos de un lenguaje de programación en concreto como Delphi.

Hay que tener conocimientos por lo menos de Interbase/Firebird por si queremos hacer una aplicación cliente/servidor y controlar la seguridad de los datos por usuarios, permisos, etc.

En lo único que yo te podría ayudar es para responder en alguna duda respecto a los artículos que he escrito, pero de ahí a sugerir como hacerse un programa paso a paso es otra cosa.

Casi no tengo tiempo de actualizar este blog semanalmente y un programa como el que pides hay que tomárselo en serio y planificarlo antes de comenzar.

Te recomiendo antes de nada, adquirir un buen conocimiento de Delphi antes de comenzar esta aventura.

Recibe un cordial saludo.

Iván Caballero Cano dijo...

Hola Amigo, gracias por compartir
tu código.

No lo puedo hechar a andar, me marca un error de memoría y no se que estoy haciendo mal.

type

THilo = class( TThread )
Ejecutar: procedure of object;
procedure Execute; override;
end;

private
{ Private declarations }
public
{ Public declarations }
end;




var
Form1: TForm1;
Hilo: THilo; // variable global o pública

implementation

{$R *.DFM}

procedure THilo.Execute;
begin
Ejecutar;
Terminate;
end;

procedure Tform1.ProcesarDatos;
begin
// Este es el procedimiento que ejecutará nuestro hilo
// Cuidado con hacer procesos críticos aquí
// El procesamiento paralelo de XP no es el de Linux
// Se puede ir por las patas abajo...
end;

procedure tform1.CrearHilo;
begin
Hilo.Ejecutar := form1.ProcesarDatos;
Hilo.Priority := tpNormal;
Hilo.Resume;
end;


me puedes decir que esta mal?

Iván Ibáñez dijo...

Hola Tocayo, tu problema es que no estas creando el Hilo.

Hilo:=THilo.Create(True);

Antes de

Hilo.Ejecutar := form1.ProcesarDatos;

Unknown dijo...

Muy bien explicado. Te cuento lo que yo quiero hacer a ver si las hebras son la mejor opción o no. Tengo una aplicación delphi que procesa un excel de entrada y genera otro de salida. El proceso es algo lento aunque esa no es la cuestión. Quiero crear una página web en la que la genta pueda subir su excel para que se procese y descargar luego el excel de resultados. Mi pregunta es, para cada llamada que reciba en la web, llamo a mi .exe o creo un .exe con varios hilos donde se vayan procesando las peticiones. Y de hacerlo así, ¿hay algún límite en el número de hilos? Gracias

Administrador dijo...

No hay ningún límite, sólo depende de la potencia del procesador y su número de núcleos.

El único inconveniente esta en que los hilos de ejecución son difíciles de depurar en caso de error, a menos que uses las últimas versiones de Delphi (que tienen IDE's tan lentos que son para morirse).

Saludos.

Unknown dijo...

Buenas Tardes como puedo implementar este codigo Hilo para que me actualize informacion cada x tiempo, si pudieran ayudarme.

Gracias

Administrador dijo...

Si no quieres calentarte la cabeza, utiliza el componente TTimer como temporizador para ejecutar algo regularmente.

Saludos.

usbrescate dijo...

Por si a alguien le sirve, yo utilize este código mediante "hilos" en lazarus para descargar un programa, pues sin hilo en la descarga congelaba la aplicación hasta que acabáse:

--------------------------------------------------
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, httpsend;

type
{ TFooThread }
TFooThread = class(TThread)
protected
procedure Execute; override;
end;

{ TForm1 }

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

function DownloadHTTP(URL, TargetFile: string): Boolean;
var
HTTPGetResult: Boolean;
HTTPSender: THTTPSend;
begin
Result := False;
HTTPSender := THTTPSend.Create;
try
HTTPGetResult := HTTPSender.HTTPMethod('GET', URL);
if (HTTPSender.ResultCode >= 100) and (HTTPSender.ResultCode<=299) then begin
HTTPSender.Document.SaveToFile(TargetFile);
Result := True;
end;
finally
HTTPSender.Free;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin

end;

procedure TForm1.FormCreate(Sender: TObject);
var
foothread: TFooThread;
begin
FooThread := TFooThread.Create(True);
// antes de que comienze el hilo aqui poner mi codigos de siempre

foothread.Start;
end;


procedure TFooThread.Execute;
begin
//while (not Terminated) and (true {any condition required}) do begin
DownloadHTTP('http://casa/usb_rescate_plus.zip','usb_rescate_plus.zip');
// do stuff
end;

end.


De tantos intentos al menos logré algo, espero les sirva, permiso.

Publicidad