Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Pomoc oko debagovanja aplikacije sa tridovima .

[es] :: Pascal / Delphi / Kylix :: Pomoc oko debagovanja aplikacije sa tridovima .

[ Pregleda: 1566 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

reikonija
Faks<lll>
Visegrad

Član broj: 213271
Poruke: 121
*.teol.net.



+4 Profil

icon Pomoc oko debagovanja aplikacije sa tridovima .07.02.2012. u 21:04 - pre 148 meseci
Moja aplikacija pokrece 2 trida (en. threads) koja prvo preko kriticne sekcije uzimaju broj linka koji skidaju u tstringlist i preradjuju tj. parsuju i dodaju preko kriticne sekciju u glvani form1 trid.

Moj problem je :
1. Kako da podesim timeout u tridu , sta ako korisnik izgubi internet konekciju ili ako mu konekcija oslabi npr. ako je na javnom wifi , zelim da trid prekine i dealocira sve resurse , sad ne znam dal mi je bolje da ga ugasim unutar trida preko onterminate procedure ili da ga ugasim preko postmessage i pustim glavni trid da ga pravilno oslobodi.
2. Imam problem prilikom gasenja trida , uslov je ako trid preradi npr 60 linkova koje dadaje u listbox u glavnom programu ja ga gasim tj. preko for petlje gasim broj tridova koji je pokrenut (tu imam neki problem)
3. Bilo kakve sugestije kako da poboljsam trid jer sa svojim znanjem mislim da i nisam nesto napravio , opet mi je glavni trid ponekad blokiran.

Kod glavnog trida :

Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OverbyteIcsWndControl, OverbyteIcsHttpProt, StdCtrls,Unit2, Spin;
const
  WM_DATA_IN_BUF = WM_APP + 1000;

type
  TForm1 = class(TForm)
    HttpCli1: THttpCli;
    Button1: TButton;
    ListBox1: TListBox;
    Memo1: TMemo;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FStringSectInit: boolean;
    FGoogle: array [0..1] of TGoogle;
    FStringBuf: TStringList;
    FLink:integer;
    procedure HandleNewData(var Message: TMessage); message WM_DATA_IN_BUF;
  public
     StringSection: TRTLCriticalSection;
    property StringBuf: TStringList read FStringBuf write FStringBuf;
    property Link: integer read FLink write FLink;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
  if not FStringSectInit then
  begin
    form1.FLink:=0;
    InitializeCriticalSection(StringSection);
    FStringBuf := TStringList.Create;
    FStringSectInit := true;
     for i:=0 to 1 do
     begin
    FGoogle[i]:= TGoogle.Create(true);
    SetThreadPriority(FGoogle[i].Handle, THREAD_PRIORITY_BELOW_NORMAL);
    FGoogle[i].Resume;
    end;
    end;
    end;





procedure TForm1.HandleNewData(var Message: TMessage);
var k,i,s:integer;

begin
  if FStringSectInit then
  begin
    EnterCriticalSection(StringSection);
    s:=flink;
    inc(s,8);
    flink:=s;

    memo1.Lines.Add(FStringBuf.Text);

    FStringBuf.Clear;
    LeaveCriticalSection(StringSection);
    {Now trim the Result Memo.}
  end;
  if form1.Memo1.Lines.Count>20 then
for k:=0 to 1 do
  begin

  fgoogle[k].Terminate;
  fgoogle[k].WaitFor;
  fgoogle[k].Free;
  FStringBuf.Free;
  DeleteCriticalSection(StringSection);
  FStringSectInit := false;
   memo1.Lines.Add('Ugasen je trid: ' + inttostr(k));

   end;
   end;

procedure TForm1.Button2Click(Sender: TObject);
begin
listbox1.Clear;
end;

end.


Kod trida koji treba da obavlja 'teski' posao:

Code:
unit Unit2;

interface

uses
  Classes,Windows,IDHTTP, OverbyteIcsWndControl, StdCtrls,OverbyteIcsHttpProt,SysUtils,Dialogs;

type
  TGoogle = class(TThread)
  private
google:TStringList;
    Upit:string;
    Broj:integer;
    Buffer : TStringList;
    httpcli1:THTTPcli;
  protected
    procedure parsegoogleapi;
    procedure SkiniSors;
    procedure Execute; override;
  public
    property StartNum: integer read Broj write Broj;
  end;

implementation
uses unit1,StrUtils;

function ExtractText(const Str, Delim1, Delim2: string; PosStart: integer; var PosEnd: integer): string;
var
 pos1, pos2: integer;
begin
    Result := '';
    pos1 := PosEx(Delim1, Str, PosStart);
    if pos1 > 0 then
    begin
    pos2 := PosEx(Delim2, Str, pos1 + Length(Delim1));
    if pos2 > 0 then
    begin
      PosEnd := pos2 + Length(Delim2);
      Result := Copy(Str, pos1 + Length(Delim1), pos2 - (pos1 + Length(Delim1)));
end;
end;
end;
function ChangeString(const Value: string; replace:string): string;
var i: Integer;
begin
    Result := '';
    for i := 1 to Length(Value) do
    if Value[i] = ' ' then
    Result := Result + replace
    else
    Result := Result + Value[i]
end;

(*Ovo je procedura za skidanje sorsa*)

procedure TGoogle.SkiniSors;
var
criter:string;

begin
HttpCli1:=THttpCli.Create(nil);
google:=TStringList.Create;
criter:= ChangeString(Upit,'%20');

With HttpCli1 do begin
    URL            := 'http://ajax.googleapis.com/aja...es/search/web?v=1.0&start=' + inttostr(broj) + '&rsz=large&q=rocksongs';
    RequestVer     := '1.1';
    Connection := 'Keep-Alive';
    RcvdStream := TMemoryStream.Create;
    try
        Get;
    except
        RcvdStream.Free;
        Exit;
        (*How can I terminate thread here if I get error*)
    end;
RcvdStream.Seek(0,0);
google.LoadFromStream(RcvdStream);
RcvdStream.Free;
ParseGoogleApi;
end;
end;

procedure TGoogle.ParseGoogleApi;
var Pos: integer;
    sText: string;
begin
Buffer:= TStringList.Create;
  sText := ExtractText(google.Text, '"url":"', '","visibleUrl"', 1, Pos);
  while sText <> '' do
  begin
    buffer.Add(sText);
        sText := ExtractText(google.Text, '"url":"', '","visibleUrl"', Pos, Pos);
  end;
  google.Clear;
end;


procedure TGoogle.Execute;
var i:integer;
begin
 while not terminated do
  begin
  EnterCriticalSection(Form1.StringSection);
  Broj:=form1.Link;
  skinisors;

  Form1.StringBuf.Add(buffer.Text);
  LeaveCriticalSection(Form1.StringSection);
  PostMessage(Form1.Handle, WM_DATA_IN_BUF, 0, 0);

  end;
Google.Free;
Buffer.Free;
httpcli1.Free;
end;
end.


Neko mi je predlozio da idem skidanje sorsa u tridu i prebacivanjem u glavni trid da ostavim posao parsiranja glavnom tridu , sad ne znam dal je to pametno.
Hvala na odgovorima , muci me ovo vec duze vreme.
 
Odgovor na temu

reiser

Član broj: 7895
Poruke: 2314



+102 Profil

icon Re: Pomoc oko debagovanja aplikacije sa tridovima .07.02.2012. u 22:08 - pre 148 meseci
Nisam ni ja neki guru za threadove, ali mi se na prvi pogled ovo cini kao vrlo lose realizovano resenje, recimo, ti iz threada pristupas form objektu, dok je to dozvoljeno samo unutar Synchronize() procedure, tj u threadu ne smes da pristupas non-thread-safe objektima.

Takodje, google ajax api vraca rezultat kao JSON, tako da bih ti preporucio da koristis neki JSON parser za to, recimo JSON – SuperObject
 
Odgovor na temu

reiser

Član broj: 7895
Poruke: 2314



+102 Profil

icon Re: Pomoc oko debagovanja aplikacije sa tridovima .08.02.2012. u 00:51 - pre 148 meseci
Evo, nije me mrzelo da ti odradim ovo, a i meni je bilo zanimljivo :)

Imas uGoogleThread (TThdGoogle klasa) i uGoogleThreadManager (TThdGoogleManager) klasa unite.

Ti ne bi trebao da imas nikakvog kontakta sa TThdGoogle klasom, osim sto se struktura TURLItem nalazi u njoj, pa zbog toga moras da stavis uGoogleThread u uses u implementation delu unita koji pripada tvojoj formi.

TThdGoogle klasa skida stranicu sa neta, parsuje je pomocu JSON SuperObjecta i poziva FOnNewData() proceduru, tj property koji ti prilikom kreiranja klase assignujes na neku proceduru.
Nakon skidanja se setuje FPaused property klase na TRUE, i ceka se da se thread odpauzira, tj da se pozove Unpaused() funkcija. Za ovo sam koristio event-driven mehanizam (CreateEvent, SetEvent, ResetEvent, WaitForSingleObject). Mogao sam da umesto WaitForSingleObject(FPauseEvent, INFINITE) stavim While FPaused Do Sleep(), ali je pristup sa eventima mnogo bolji (ne trosi dodatni CPU).

TThdGoogleManager klasa obavlja menadzment TThdGoogle threadova, tj prvo ih kreira, zatim kada thread zavrsi sa radom (tj FPaused property bude TRUE), povecava mu LinkIndex na sledeci koji treba da se skine sa neta i poziva .Unpause(), tj kaze mu da nastavi sa radom.

uGoogleThread.pas
Code:

unit uGoogleThread;

interface

uses
  Classes, OverbyteIcsWndControl, OverbyteIcsHttpProt;

type
  PURLItem = ^TURLItem;
  TURLItem = record
               URL        : String;
               VisibleURL : String;
             end;

  TOnNewData = procedure(const AData : TList) of object;

  TThdGoogle = class(TThread)
               private
                 FHTTPClient : THttpCli;
                 FLinkIndex  : Integer;
                 FURLList    : TList;
                 FProxy      : String;
                 FForm       : pointer;
                 FPaused     : Boolean;
                 FPauseEvent : THandle;
                 FOnNewData  : TOnNewData;

                 procedure ClearURLList;
                 procedure HttpRequestDone(Sender: TObject; RqType: THttpRequest; ErrCode: Word);
                 procedure UpdateData;
                 procedure SetLinkIndex(const AValue : Integer);
               protected
                 procedure Execute; override;
               public
                 constructor Create(const AForm : pointer; const ALinkIndex : Integer; const AProxy : String = '');

                 procedure Unpause;

                 property LinkIndex : Integer read FLinkIndex write SetLinkIndex;
                 property Paused    : Boolean read FPaused;
                 property OnNewData : TOnNewData read FOnNewData write FOnNewData;
               end;

implementation

uses
  Windows, SysUtils, superobject;



constructor TThdGoogle.Create(const AForm : pointer; const ALinkIndex : Integer; const AProxy : String = '');
begin
  FForm := AForm;
  FLinkIndex := ALinkIndex;
  FProxy := AProxy;
  FPaused := FALSE;

  inherited Create(FALSE);
end;

procedure TThdGoogle.Unpause;
begin
  SetEvent(FPauseEvent);
end;

procedure TThdGoogle.UpdateData;
begin
  If Assigned(FOnNewData) Then
    FOnNewData(FURLList);
end;

procedure TThdGoogle.ClearURLList;
var
  C1 : Integer;
begin
  If Assigned(FURLList) Then
  Begin
    For C1 := 0 to FURLList.Count - 1 Do
      Dispose(PURLItem(FURLList[C1]));
    FURLList.Clear;
  End;
end;

procedure TThdGoogle.SetLinkIndex(const AValue : Integer);
begin
  If FPaused Then
    FLinkIndex := AValue;
end;

procedure TThdGoogle.Execute;
var
  Success : Boolean;
begin
  FPauseEvent := CreateEvent(nil, FALSE, FALSE, nil);

  FURLList := TList.Create;

  FHTTPClient := THTTPCli.Create(Nil);
  FHTTPClient.MultiThreaded := TRUE;
  FHTTPClient.RcvdStream := TMemoryStream.Create;
  FHTTPClient.Proxy := FProxy;
  FHTTPClient.OnRequestDone := HttpRequestDone;
  FHTTPClient.Timeout := 5;

  While not Terminated Do
  Begin
    FPaused := FALSE;
    SetEvent(FPauseEvent);

    FHTTPClient.URL := Format('http://ajax.googleapis.com/aja...&rsz=large&q=rocksongs', [FLinkIndex]);
    (FHTTPClient.RcvdStream as TMemoryStream).Clear;

    ClearURLList;
    try
      FHTTPClient.Get;
      Success := TRUE;
    except
      Success := FALSE;
    end;

    If (not Terminated) and
       (Success) THen
    Begin
      Synchronize(UpdateData);
      FPaused := TRUE;
      ResetEvent(FPauseEvent);
      WaitForSingleObject(FPauseEvent, INFINITE);
    End;
  End;

  If Assigned(FHTTPClient.RcvdStream) Then
    FHTTPClient.RcvdStream.Free;
  FHTTPClient.Free;

  ClearURLList;
  FURLList.Free;

  CloseHandle(FPauseEvent);
end;

procedure TThdGoogle.HttpRequestDone(Sender: TObject; RqType: THttpRequest; ErrCode: Word);
var
  JSON            : ISuperObject;
  jsonItem        : ISuperObject;
  response        : String;
  urlItem         : PURLItem;
begin
  If ErrCode <> 0 Then
  Begin
    // err handling, errcode <> 0
  End
  else
  Begin
    If THTTPCli(Sender).StatusCode <> 200 Then
    Begin
      // err handling, statuscode <> 200
    End
    else
    Begin
      If (Assigned(THTTPCli(Sender).RcvdStream)) and
         (THTTPCli(Sender).RcvdCount > 0) Then
      Begin
        THTTPCli(Sender).RcvdStream.Position := 0;
        JSON := TSuperObject.ParseStream(THTTPCli(Sender).RcvdStream, FALSE);
        response := JSON.AsString;

        If (JSON.S['responseData'] <> '') and
           (JSON['responseData'].S['results'] <> '' ) Then
          For jsonItem in JSON['responseData']['results'] Do
          Begin
            New(urlItem);
            urlItem^.URL := jsonItem.S['url'];
            urlItem^.VisibleURL := jsonItem.S['visibleUrl'];
            FURLList.Add(urlItem);
          End;

        JSON := nil;
      End
      else
      Begin
        // err handling, received count = 0
      End;
    End;
  End;
end;

end.


uGoogleThreadManager.pas
Code:

unit uGoogleThreadManager;

interface

uses
  Classes, uGoogleThread;

type
  TThdGoogleManager = class(TThread)
                      private
                        FThreadCount : Integer;
                        FThreads     : Array of TThdGoogle;
                        FStartIndex  : Integer;
                        FStep        : Integer;
                        FForm        : pointer;
                        FNextIndex   : Integer;
                        FOnNewData   : TOnNewData;
                      protected
                        procedure Execute; override;
                      public
                        constructor Create(const AForm : pointer; const AThreadCount : Integer; const AStartIndex : Integer = 0; const AStep : Integer = 8);

                        property ThreadCount : Integer read FThreadCount;
                        property OnNewData : TOnNewData read FOnNewData write FOnNewData;
                      end;

implementation

uses
  Windows, SysUtils;

constructor TThdGoogleManager.Create(const AForm : pointer; const AThreadCount : Integer; const AStartIndex : Integer = 0; const AStep : Integer = 8);
begin
  inherited Create(TRUE);

  FForm := AForm;
  FStartIndex := AStartIndex;
  FStep := AStep;
  FThreadCount := AThreadCount;
  SetLength(FThreads, FThreadCount);
end;

procedure TThdGoogleManager.Execute;
var
  C1 : Integer;
begin
  FNextIndex := FStartIndex;

  While not Terminated Do
  Begin
    For C1 := 0 to FThreadCount - 1 Do
      If not Assigned(FThreads[C1]) Then
      Begin
        FThreads[C1] := TThdGoogle.Create(FForm, FNextIndex);
        FThreads[C1].OnNewData := FOnNewData;
        Inc(FNextIndex, FStep);
      End
      else
      Begin
        If FThreads[C1].Paused Then
        Begin
          FThreads[C1].LinkIndex := FNextIndex;
          FThreads[C1].OnNewData := FOnNewData;
          Inc(FNextIndex, FStep);
          FThreads[C1].Unpause;
        End;
      End;

    Sleep(50);
  End;

  For C1 := 0 to FThreadCount - 1 Do
    If Assigned(FThreads[C1]) Then
    Begin
      FThreads[C1].Terminate;
      FThreads[C1].Unpause;
      FThreads[C1].WaitFor;
      FThreads[C1].Free;
    End;
end;

end.


uMainWindow.pas
Code:

unit uMainWindow;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uGoogleThreadManager;

type
  TMainWindow = class(TForm)
    btStart: TButton;
    btClear: TButton;
    Memo: TMemo;
    procedure btStartClick(Sender: TObject);
    procedure btClearClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure StopThreadManager;
  private
    FThdGoogle : TThdGoogleManager;

    procedure OnNewData(const AData : TList);
  public
  end;

var
  MainWindow: TMainWindow;

implementation

{$R *.dfm}

uses
  superobject, uGoogleThread;

procedure TMainWindow.btClearClick(Sender: TObject);
begin
  Memo.Clear;
end;

procedure TMainWindow.StopThreadManager;
begin
  FThdGoogle.Terminate;
  FThdGoogle.WaitFor;
  FreeAndNil(FThdGoogle);
end;

procedure TMainWindow.btStartClick(Sender: TObject);
begin
  If Assigned(FThdGoogle) Then
  Begin
    StopThreadManager;
    TButton(Sender).Caption := 'Start';
  End
  else
  Begin
    FThdGoogle := TThdGoogleManager.Create(self, 4);
    FThdGoogle.OnNewData := OnNewData;
    FThdGoogle.Start;
    TButton(Sender).Caption := 'Stop';
  End;
end;

procedure TMainWindow.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  If Assigned(FThdGoogle) Then
    StopThreadManager;
end;

procedure TMainWindow.OnNewData(const AData : TList);
var
  item : TURLItem;
  C1   : Integer;
begin
  For C1 := 0 to AData.Count - 1 Do
  Begin
    item := TURLItem(AData[C1]^);
    Memo.Lines.Add(item.URL);
    Memo.Lines.Add(item.VisibleURL);
    Memo.Lines.Add('');
  End;
end;

end.


Ceo projekat u attachu.
Prikačeni fajlovi
 
Odgovor na temu

reikonija
Faks<lll>
Visegrad

Član broj: 213271
Poruke: 121
*.teol.net.



+4 Profil

icon Re: Pomoc oko debagovanja aplikacije sa tridovima .12.02.2012. u 20:44 - pre 148 meseci
Hvala na extra kodu , i sto si nasao vremena da mi to postavis i na download , tvoj pristup je daleko drugaciji od moga , ali je i daleko funkcionalniji.....
 
Odgovor na temu

[es] :: Pascal / Delphi / Kylix :: Pomoc oko debagovanja aplikacije sa tridovima .

[ Pregleda: 1566 | Odgovora: 3 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.