Ir al contenido


Foto

Ayuda con creación de hilos con TThread


  • Por favor identifícate para responder
12 respuestas en este tema

#1 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 10:29

Pues eso, por primera vez estoy trabajando con hilos (TThread), llevo lo siguiente:



delphi
  1. unit DDownloader;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs, zkemkeeper_TLB, XPMan, ComCtrls, StdCtrls;
  8.  
  9. type
  10.   TFMain = class(TForm)
  11.     Label1: TLabel;
  12.     lbNetAddress: TLabel;
  13.     Label4: TLabel;
  14.     lbStatus: TLabel;
  15.     Label6: TLabel;
  16.     lbDevStatus: TLabel;
  17.     Label8: TLabel;
  18.     lbTotalDatos: TLabel;
  19.     Label2: TLabel;
  20.     lbPercent: TLabel;
  21.     Label3: TLabel;
  22.     lbModel: TLabel;
  23.     Button2: TButton;
  24.     Button3: TButton;
  25.     Button4: TButton;
  26.     pbProgreso: TProgressBar;
  27.     sbInfo: TStatusBar;
  28.     XPManifest1: TXPManifest;
  29.   private
  30.     { Private declarations }
  31.   public
  32.     { Public declarations }
  33.   end;
  34.  
  35.   TDataDown = class(TThread)
  36.   private
  37.     { Private declarations }
  38.     DevID: Integer;
  39.     ZK: TCZKEM;
  40.     strFirmWare: WideString;
  41.     Connected: Boolean;
  42.     FPercent: WideString;
  43.   protected
  44.     procedure Execute; override;
  45.     procedure MostrarProgreso; override;
  46.   public
  47.     { Public declarations }
  48.     IPAddress: WideString;
  49.   end;
  50.  
  51. var
  52.   FMain: TFMain;
  53.  
  54. implementation
  55.  
  56. {$R *.dfm}
  57.  
  58. procedure TDataDown.Execute;
  59. var
  60.   i: Integer;
  61.   dwEnrollNumber,dwModel: widestring;
  62.   dwYear,dwMonth,dwDay,dwHour,dwMinute,dwSecond: Integer;
  63.   dwVerifyMode,dwInOutMode,dwWorkCode: integer;
  64.   s: string;
  65.   f: TFileStream;
  66.   Data: TStringList;
  67.   Connect: Boolean;
  68.   ErrorCode: Integer;
  69.   Fecha: TDateTime;
  70. begin
  71.   Connect := ZK.Connect_Net(IPAddress,4370);
  72.   DevID := 1;
  73.   ZK.GetFirmwareVersion(DevID, strFirmWare);
  74.   ZK.GetProductCode(DevID,dwModel);
  75.   FMain.lbModel.Caption := dwModel;
  76.   FMain.sbInfo.Panels[1].Text  := 'Firm Version: '+strFirmWare;
  77.   if Connect then Begin
  78.     Connected := True;
  79.     FMain.lbDevStatus.Caption :=  'Activo';
  80.     Data  := TStringList.Create;
  81.     f := TFileStream.Create(ExtractFilePath(Application.ExeName)+ FormatDateTime('yy-mm-dd',Now)+'.D1', fmOpenWrite or fmCreate);
  82.     try
  83.     Data.Clear;
  84.     FMain.lbStatus.Caption  :=  'Trabajando...';
  85.     if ZK.ReadAllGLogData(DevId) then
  86.     while ZK.SSR_GetGeneralLogData(DevId,dwEnrollNumber,dwVerifyMode,dwInOutMode,
  87.                                   dwYear,dwMonth,dwDay,dwHour,dwMinute,dwSecond,dwWorkCode) do
  88.     begin
  89.       ShortDateFormat := 'yyyy/mm/dd';
  90.       ShortTimeFormat := 'hh:mm';
  91.       TimeSeparator := ':';
  92.       DateSeparator := '/';
  93.       Fecha := StrToDateTime(IntToStr(dwYear)+'/'+IntToStr(dwMonth)+'/'+IntToStr(dwDay)+' '+IntToStr(dwHour)+':'+IntToStr(dwMinute));
  94.       s := format('%.*d',[7,StrToInt(dwEnrollNumber)])+'>'+FormatDateTime('yyyy/mm/dd', Fecha)+':'+FormatDateTime('hh:mm', Fecha) + Char(#13) + Char(#10);
  95.       Data.Add(s);
  96.     end;
  97.  
  98.   if (Data.Count > 0) then
  99.     begin
  100.  
  101.     FMain.lbTotalDatos.Caption  :=  IntToStr(Data.Count);
  102.     FMain.pbProgreso.Max  :=  Data.Count;
  103.  
  104.     for I := 0 to Data.Count - 1 do begin
  105.       if Terminated then Exit;
  106.       FPercent := FloatToStr((Data.IndexOf(Data.Strings[i]) * 100) / Data.Count)+'%';
  107.       f.WriteBuffer(Data.Strings[i][1], Length(Data.Strings[i]));
  108.       Synchronize(MostrarProgreso);
  109.     end;
  110.   end else ShowMessage('No Hay datos que descargar!.');
  111.      
  112.     finally
  113.       Data.Free;
  114.       f.Free;
  115.       Connected :=  False;
  116.     end;
  117.   End else begin
  118.     Connected :=  False;
  119.     ZK.GetLastError(ErrorCode);
  120.     FMain.lbDevStatus.Caption := 'Inactivo';
  121.     FMain.lbStatus.Caption  := 'Esperando...';
  122.     FMain.lbTotalDatos.Caption  :=  '0';
  123.     ShowMessage('Ha Ocurrido un Problema!. Error No.: '+IntToStr(Errorcode));
  124.   end;
  125.   FMain.lbTotalDatos.Caption  :=  '0';
  126.   FMain.lbStatus.Caption := 'Esperando...';
  127.   FMain.lbDevStatus.Caption :=  'Inactivo';
  128.   ZK.Disconnect;
  129. end;
  130.  
  131. procedure TDataDown.MostrarProgreso;
  132. begin
  133.   FMain.lbPercent.Caption := FPercent;
  134. end;
  135.  
  136. end.



Como verán TDataDown es el hilo que estoy creando y ella tiene dos métodos, Execute y MostrarProgreso, pues bien, al querer compilar el proyecto me da el siguiente error:



delphi
  1. [Error] DDownloader.pas(45): Method 'MostrarProgreso' not found in base class



Donde estoy fallando???

Saludos.
  • 0

#2 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 12 octubre 2010 - 11:04

El problema es que estas usando "override" en un método que no esta declarado en la clase "padre", simplemente elimina la directiva override de la declaración de MostrarProgreso

Es decir, lo correcto sería:


delphi
  1. TDataDown = class(TThread)
  2.   private
  3.     { Private declarations }
  4.     DevID: Integer;
  5.     ZK: TCZKEM;
  6.     strFirmWare: WideString;
  7.     Connected: Boolean;
  8.     FPercent: WideString;
  9.   protected
  10.     procedure Execute; override;
  11.     procedure MostrarProgreso; // Eliminamos el override
  12.   public
  13.     { Public declarations }
  14.     IPAddress: WideString;
  15.   end;


  • 0

#3 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 11:17

Gracias seoane, en efecto ese era el problema, gracias (y), ahora me falta ejecutar esa clase desde un button, hice lo siguiente:



delphi
  1. procedure TFMain.Button3Click(Sender: TObject);
  2. begin
  3.   TDataDown.Create(False);
  4. end;



pero me causa el siguiente error:



delphi
  1. ---------------------------
  2. Debugger Exception Notification
  3. ---------------------------
  4. Project PDownloader.exe raised exception class EAccessViolation with message 'Access violation at address 004618BA in module 'PDownloader.exe'. Read of address 000002F0'. Process stopped. Use Step or Run to continue.
  5. ---------------------------
  6. OK  Help 
  7. ---------------------------



Cual es la forma correcta de llamar esa clase??

Saludos.

  • 0

#4 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 12 octubre 2010 - 11:30

El problema no es del thread, yo mas bien creo que el problemas esta en que no creas en ningún sitio el objeto "ZK: TCZKEM", por eso al usarlo en la primera linea del execute te da un error.
  • 0

#5 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 11:36

El problema no es del thread, yo mas bien creo que el problemas esta en que no creas en ningún sitio el objeto "ZK: TCZKEM", por eso al usarlo en la primera linea del execute te da un error.


Ah caray, que wey soy, en efecto se me ha olvidado crear "ZK" en algún lado :D :D, de nuevo, muchas gracias (y).

PD. Aún no doy por terminado el tema :p

Saludos.
  • 0

#6 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 12 octubre 2010 - 11:40

Pues ya que esta revisando el código recuerda que desde el thread no puedes acceder a los componentes visuales sin usar el synchronize, asi que todos esos "FMain...." fuera del execute  :p
  • 0

#7 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 11:42

mmm, lo que pasa es que esos componentes visuales pertenecen a la Clase TFMain, de todos modos así como está me acaba de funcionar perfectamente.

Saludos.
  • 0

#8 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 12 octubre 2010 - 11:49

mmm, lo que pasa es que esos componentes visuales pertenecen a la Clase TFMain, de todos así como está me acaba de funcionar perfectamente.

Saludos.


Que funcione bien, ahora, no quiere decir que este bien. El cualquier momento puede haber una "colision" entre el hilo principal donde están esos componentes y el thread. Tienes que meter todo eso dentro de un metodo del thread y usar synchronize.
  • 0

#9 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 12:01

Que funcione bien, ahora, no quiere decir que este bien. El cualquier momento puede haber una "colision" entre el hilo principal donde están esos componentes y el thread. Tienes que meter todo eso dentro de un metodo del thread y usar synchronize.


No acabo de entender esa última parte, me podrías un simple ejemplo si es posible?.

Saludos.
  • 0

#10 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 12:21

Saludos.

Amigo si tienes las JEDI instaladas, puedes usar el componente TJvThread más algunos que este necesita para sincronización y demás.
  • 0

#11 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 12 octubre 2010 - 12:37

Saludos.

Amigo si tienes las JEDI instaladas, puedes usar el componente TJvThread más algunos que este necesita para sincronización y demás.


Gracias amigo Rolphy, ya las conocía, pues las tengo instaladas, pero en este caso trato de evitar el uso de componentes de terceros ;).

Saludos.
  • 0

#12 Kipow

Kipow

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 228 mensajes
  • LocationGuatemala

Escrito 12 octubre 2010 - 03:12

Proba ejecutar 2 veces tu codigo y seguro falla, el synchronize te ayuda a evitar eso por eso toda utilizacion de la VCL debe de ser llamada dentro de un procedimiento con synchronize para evitar la colision ya que las vcl no son theadsafe. Me imagino que la idea de hacerlo con threads es para realizar descargas simultaneas?
  • 0

#13 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 13 octubre 2010 - 09:14

Proba ejecutar 2 veces tu codigo y seguro falla, el synchronize te ayuda a evitar eso por eso toda utilizacion de la VCL debe de ser llamada dentro de un procedimiento con synchronize para evitar la colision ya que las vcl no son theadsafe. Me imagino que la idea de hacerlo con threads es para realizar descargas simultaneas?


Hola Kipow, no es simultáneas ya que se realiza una sola vez, la idea de hacerlo con hilos es que al realizar descargas de muchos datos (2,000 a 4,000 registros) la aplicación queda congelada y da la impresión que está fallando, ahora con Hilos he resuelto ese problema, Pero de todos modos gracias por el TIP lo tomaré en cuenta en caso de que haya descargas simultáneas.

Saludos.
  • 0




IP.Board spam blocked by CleanTalk.