Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Dudas con Hilo en ejecución (https://www.clubdelphi.com/foros/showthread.php?t=84451)

danielmj 20-10-2013 21:47:40

Dudas con Hilo en ejecución
 
Hola, espero que podais echarme una mano con esto, a ver tengo un boton que hace una llamada a una función, esta realiza una tarea pesada que incluso llega a congelar la aplicación, por ese motivo he empezado a mirarme los hilos y ver un poco como funcionan, me he bajado el pdf de "delphi al limite" ademas de mirar por la web, pero no me aclaro. El problema es que la llamada a la función es la siguiente:

Código Delphi [-]
Procedure TPrincipal.Button1Click(Sender: TObject);
begin
  CortarArchivo(labEdit1.Text,2048);
end;

Y el error que me da al usar el hilo es este...


Como veis, la llamada a la función tiene dos parametros, entonces, suponiendo que fuera button1.Click el encargado de ejecutar el hilo y este a su vez hace la llamada a la función ¿como seria? o dicho de otro modo ¿como le paso al hilo esa función para que ejecute todo el código?

No sé si me he explicado bien, espero que si. Saludos y ojalá podais ayudarme.

Casimiro Notevi 20-10-2013 22:31:52

Ufff, creo que es más fácil un simple copia y pega del mensaje, ¿no crees? ;)
Cita:

[dcc32 Error] ZIZ.pas(784): E2010 Incompatible types: 'TThreadMethold' and 'procedure', untyped pointer or untyped parameter'

ecfisa 20-10-2013 22:46:40

Hola danielmj.

Publicá la declaración de la tu clase TThread y del procedimiento "CortarArchivo". Por el texto del mensaje de error y por como realizas la llamada, parece que lo has declarado como un procedimiento normal y no como método de una clase TThread.

Saludos :)

danielmj 20-10-2013 22:58:28

Cita:

Empezado por Casimiro Notevi (Mensaje 468690)
Ufff, creo que es más fácil un simple copia y pega del mensaje, ¿no crees? ;)

:o jaja es cierto, me complique mas de la cuenta. Saludos.

danielmj 20-10-2013 23:17:02

Hola ecfisa, saludos

mira..

Declaración del hilo...
Código Delphi [-]
...
private
{ Private declarations }
Thread: TStopStartThread;
WaitThread: TWaitThread;
UntilFlag: TEvent;
...

hago la llamada al hilo...
Código Delphi [-]
Procedure TPrincipal.Button1Click(Sender: TObject);
begin
  Thread.MsgWaitFor(CortarArchivo(labEdit1.Text,2048), nil); //---> Aquí me da el error o uno de los que posiblemente me vaya a dar.
  //CortarArchivo(labEdit1.Text,2048); --> esta linea esta operativa en este momento ya que el hilo  lo tengo "anulado" por no correr.
end;

Procedimiento "CortarArchivo"...
Código Delphi [-]
procedure CortarArchivo(sArchivo: TFileName; iLongitudTrozo: Long64 );
var
  i: Word;
  FS, Stream: TFileStream;
  nombreFile: String;

  label iniciar;

begin
  try
    principal.memo1.Lines.Add(CalcHash(principal.labedit1.Text,haSHA1));
    principal.Memo1.Lines.SaveToFile(principal.labEdit2.Text+ '\'+ extractFileName(principal.LabEdit1.Text+'.crc'));
  except
    on EFCreateError do
      begin
        showMessage ('Unidad seleccionada no válida. Selecciona una unidad' +
        chr(13)+'de disco duro local que sea accesible.');
        principal.Memo1.Text:= '';
        exit;
      end;
  end;

    if principal.opc1.Checked then
    begin
      iLongitudTrozo:= 1048576;        //1MB  --> los tamaños se muestran en Mbytes
      //sArchivo:= principal.LabEdit2.Text;

      FS := TFileStream.Create(sArchivo, fmOpenRead or fmShareDenyWrite);
    try
      principal.Memo2.Lines.Add((Chr(13))+(Chr(10)));
      principal.Memo2.Lines.Add('LISTADO DE ARCHIVOS [ORIGINAL CORTADO]');
      principal.Memo2.Lines.Add((Chr(13))+(Chr(10))+'·································');

      for i := 1 to Trunc( FS.Size / iLongitudTrozo ) + 1 do
      begin
        principal.prBar.Max:= FS.Size div iLongitudTrozo;
        principal.prBar.Position:= i;
        principal.prBar.Refresh;

        nombreFile:= extractFileName(sArchivo);
        try
          sArchivoPartido := ChangeFileExt(principal.labEdit2.Text +'\'+
          nombreFile, '.' + FormatFloat('000', i ) );
          Stream := TFileStream.Create(sArchivoPartido, fmCreate or fmShareExclusive);
        except
        on EFileStreamError do
        ShowMessage ('Unidad seleccionada no valida. Selecciona una unidad de disco duro local.');

        end;
          principal.labEdit2.SelStart:= 0;
          principal.labEdit2.SelLength:= length(principal.labEdit2.Text);
        if (principal.labEdit2.SelLength) = 3 then
            principal.Memo2.Lines.Append(principal.labEdit2.Text + extractFileName(sArchivoPartido))
        else
          principal.Memo2.Lines.Append(principal.labEdit2.Text+'\'+extractFileName(sArchivoPartido));

      try
        if fs.Size - fs.Position < iLongitudTrozo then
          iLongitudTrozo := FS.Size - FS.Position;
          Stream.CopyFrom( FS, iLongitudTrozo );
      finally
        Stream.Free;
      end;
  end;
  finally
  FS.Free;
  principal.Button1.Enabled:= false;

  principal.Memo2.Lines.Add((Chr(13))+ (chr(10)));
  principal.Memo2.Lines.Add('Archivo original: '+principal.LabEdit1.Text);
  principal.memo2.Lines.Add('Ruta destino: '+principal.labEdit2.Text);
  principal.Memo2.Lines.Add('Código HASH: '+principal.Memo1.Text);

  end;
    if principal.prBar.Max = principal.prBar.Position then
    principal.Timer1.Enabled:= true;
    Principal.lblTerminado.Visible:= true;
end;
...
    if principal.opc1.Checked then
    begin
      iLongitudTrozo:= 16106127360;        //15GB
      FS := TFileStream.Create( sArchivo, fmOpenRead or fmShareDenyWrite);
    try
      Principal.Label6.Caption:= IntToStr((FS.Size div iLongitudTrozo) +1);
      principal.Label6.Refresh;

      principal.Memo2.Lines.Add((Chr(13))+(Chr(10)));
      principal.Memo2.Lines.Add('LISTADO DE ARCHIVOS [ORIGINAL CORTADO');
      principal.Memo2.Lines.Add((Chr(13))+(Chr(10))+'·································');

      for i := 1 to Trunc( FS.Size / iLongitudTrozo ) + 1 do
      begin

        principal.prBar.Max:= Round((FS.Size / iLongitudTrozo));
        principal.prBar.Position:= i;
        principal.prBar.Refresh;

        sArchivoPartido := ChangeFileExt(principal.labEdit2.Text +'\'+
        nombreFile, '.' + FormatFloat('000', i ) );
        Stream := TFileStream.Create(sArchivoPartido, fmCreate or fmShareExclusive);

        principal.labEdit2.SelStart:= 0;
        principal.labEdit2.SelLength:= length(principal.labEdit2.Text);
        if (principal.labEdit2.SelLength) = 3 then
            principal.Memo2.Lines.Append(principal.labEdit2.Text + extractFileName(sArchivoPartido))
        else
          principal.Memo2.Lines.Append(principal.labEdit2.Text+'\'+extractFileName(sArchivoPartido));
      try
        if fs.Size - fs.Position < iLongitudTrozo then
          iLongitudTrozo := FS.Size - FS.Position;
          Stream.CopyFrom( FS, iLongitudTrozo);
      finally
        Stream.Free;
      end;
  end;
  finally
  FS.Free;
  principal.Button1.Enabled:= false;

  principal.Memo2.Lines.Add((Chr(13))+ (chr(10)));
  principal.Memo2.Lines.Add('Archivo original: '+principal.LabEdit1.Text);
  principal.memo2.Lines.Add('Ruta destino: '+principal.labEdit2.Text);
  principal.Memo2.Lines.Add('Código HASH: '+principal.Memo1.Text);
  end;
    if principal.prBar.Max = principal.prBar.Position then
    principal.Timer1.Enabled:= true;
    Principal.lblTerminado.Visible:= true;
  end;
end;

Así está ahora mismo, ¿alguna sugerencia?
Una cosa, no seais muy duros con el código que estoy verdecillo :) ya sé que habra mil formas de hacerlo mas claro y limpio pero todo a su tiempo. De momento funciona que no es poco jajaj.

P.D.: El ejemplo que uso de hilo es de la web "crea tu software" y no sé si será valido en mi caso.

Saludos y gracias.

danielmj 21-10-2013 11:56:45

Buenas,

Ya lo tengo solucionado, el error era mi despiste y no estudiar bien las explicaciones, a ver el problema estaba (o eso entiendo) que para pasar parametros a un hilo, hay que declarar un type tal que este:

Código Delphi [-]
type
  TData = record
  Codigo: integer;
  Nombre: string;
end;

Obviamente, cambiando nombres, y esto yo no lo hacía. Por otra parte, tampoco declaraba en el uses la unidad "ActiveX", y esta es necesaria para incializar el hilo con el parametro "CoInitialize"

Código Delphi [-]
procedure TJoin.ThreadExample(Data: pointer);
begin
  CoInitialize(nil);
  UnirArchivo(labEdit1.Text,labEdit2.Text);
end;

Bueno, esa es la solución. Espero que le sirva a alguien.
Saludos.

ecfisa 21-10-2013 11:58:33

Hola danielmj.

Gracias por presentarnos la solución ^\||/

Saludos :)

danielmj 21-10-2013 13:22:18

bueno, bien o mal explicado, creo que puede ayudar a alguien o eso espero. En cuanto al hilo, ya está corriendo :D

saludos.

danielmj 22-10-2013 23:26:21

Hola nuevamente,
Parece que no es oro todo lo que reluce... y digo esto por que si bien el hilo ya corre, cuando pulso el botón para salir (o matar al hilo), no hace ni caso y el proceso sigue...

Este es código que tengo puesto para cortar el hilo definitivamente y salir de la aplicacion:
Código Delphi [-]
if Assigned(WaitThread) then WaitThread.AbortThread;
    if Thread.Waiting then Thread.AbortThread;
    begin  
      thread.Terminate;
      WaitThread.Terminate;
      FreeAndNil(thread);
      Thread.Free;
      UntilFlag.Free;
   end;
close

¿que hago mal?

Saludos y gracias.

Casimiro Notevi 23-10-2013 00:42:02

No sé que otras cosas harás mal, pero esto sí que está mal:
Código Delphi [-]
FreeAndNil(thread);
thread.Free;

Con FreeAndNil liberas la memoria ocupada y la pones a nulo. Luego con Free ... ya no hay nada que liberar, en teoría.

danielmj 23-10-2013 00:57:25

Gracias por el apunte casimiro, soy de los que piensa que hay que ser humilde en todos los aspectos de la vida de ahí que sepa reconocer mis errores. Es por eso que os pido consejo sobre tal o cual código, afortunadamente son pocas las otras cosas que hago mal, y aunque la programacion no me vaya a dar de comer (es mas una aficion) el trabajar de 7 de la mañana a 8 de la tarde en un torno paralelo o en la centina de un remolcador, si se me da bien desde hace ya 25 años.
una vez mas gracias por tu comentario lo estudiare y lo pondre en practica a ver que tal.

Casimiro Notevi 23-10-2013 01:13:43

¿Y trabajas de tornero en la sentina de un remolcador?

danielmj 23-10-2013 01:24:14

:) si te fijas en mi anterior texto use "o" para referirme a una cosa u otra, es decir dicho de modo facilmente entendible, a veces el trabajo exige que este 12 horas de pie en el torno y otras que este doblado como un 8 entre tuberias de gasoil, aceite hidraulico etc en la sentina de un barco o en la sala de maquinas de este. Y no sabes como de reventado se llega a casa... pero es lo que hay. La programacion en mi caso es mas una especie de terapia de desconexion del dia a dia y si encima aprendo pues mejor. Saludos.

Casimiro Notevi 23-10-2013 01:47:20

Sí, es un trabajo duro.

nlsgarcia 23-10-2013 02:12:42

danielmj,

Cita:

Empezado por danielmj
...La programación en mi caso es mas una especie de terapia de desconexión del día a día y si encima aprendo pues mejor...

^\||/ #:-)#

Nelson.

danielmj 23-10-2013 20:24:30

Saludos y vuelta con lo mismo...

He modificado el código como me sugería casimiro (lo que ahora no sé es si le entendí bien), el caso es es que el código queda así...
Código Delphi [-]
try
    if Assigned(WaitThread) then WaitThread.AbortThread;
      if Thread.Waiting then Thread.AbortThread;
        thread.Terminate;
        close
  except
    thread.Free;
  raise
  end;

Añado que esta modificación la hago en base a una discusión en stackoverflow que encontré no hace ni media hora. Dicho esto, cuando pulso sobre "cerrar" el formulario se cierra pero en segundo plano el hilo sigue corriendo, si pulso la "X" de cerrar me tira este error (ver captura). Si vuelvo a pulsar la "X" parar cerrar el formulario "a las bravas" se repite el mismo mensaje de error y ya luego si se cierra todo y sale del programa.

Mensaje de error 1:


Mensaje de error2 (lo muestra si pulso "continue" en el primer error):


Entonces, ¿de que forma se detiene correctamente un hilo que se esta ejecutando en el momento de detenerse?

P.D.: Saludos nelson, me alegra que estes de acuerdo con mi afirmación :cool: aunque veces la terapia me crispa los nervios jaja.

Casimiro Notevi 23-10-2013 20:37:01

Cita:

Empezado por danielmj (Mensaje 468877)
He modificado el código como me sugería casimiro (lo que ahora no sé es si le entendí bien), el caso es es que el código queda así...

je, je... aunque yo solamente comenté que sobraba el thread.free, porque ya lo habías liberado en la línea anterior con freeAndNil(thread) :)

danielmj 27-10-2013 15:37:17

hola a todos,

sigo con lo mismo, parece que se corta el hilo pero sigue con el proceso en segundo plano. ahora el código solo tiene

Código Delphi [-]
thread.terminate;
thread.freeOnterminate:= true;

Pero como digo, sigue con el proceso de unir el archivo en segundo plano, y cuando pulso la "x" para salir del formulario, me tira dos mensajes de error como las capturas de mas arriba.

¿alguna idea?
Gracias.

danielmj 27-10-2013 19:28:41

error al salir
 
Hola, ¿por que si en el boton de salir unicamente tengo "Close" me da dos errores en forma de excepcion? lo esquematizo un poco para situaros...

Código Delphi [-]
FORMULARIO PRINCIPAL
           BOTON1 --> LLAMA AL FORMULARIO CORTAR
           BOTON2 --> LLAMA AL FORMULARIO UNIR 
           BOTON3 --> SALIR
               CODIGO BOTON3 --> "close"

No entiendo por que me da error cuando solo tiene la orden de salir y cerrar la aplicacion, a no ser que haya heredado algun "estado" de los formularios cortar/unir y lo tenga en memoria a la hora de salir de la aplicacion. Pero si es por ese motivo, tampoco sé como liberarlo.
¿alguna idea? gracias y un saludo.

Casimiro Notevi 27-10-2013 20:08:22

No somos adivinos ni tenemos una bola mágica. Creo que ya has leido nuestra guía de estilo, pues eso :)


La franja horaria es GMT +2. Ahora son las 22:34:45.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi