AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

TThread Syncronise & TCriticalSection.Enter

Ein Thema von Jonas Shinaniganz · begonnen am 14. Mai 2014 · letzter Beitrag vom 15. Mai 2014
Antwort Antwort
Benutzerbild von Jonas Shinaniganz
Jonas Shinaniganz

Registriert seit: 30. Aug 2011
249 Beiträge
 
Delphi XE5 Ultimate
 
#1

TThread Syncronise & TCriticalSection.Enter

  Alt 14. Mai 2014, 18:10
Hallo Forum, aus Interesse habe ich in aller Schnelle folgende App erstellt:

Es wird in einem IP-Bereich für jede Adresse eine NSLOOKUP Anfrage gestellt.

Delphi-Quellcode:
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.Variants, System.UITypes,
  System.Classes, FMX.Types, FMX.Graphics, FMX.Dialogs, FMX.Types3D, FMX.Forms,
  FMX.Forms3D, FMX.Controls3D, IdGlobal, IdStack, FMX.Layers3D, FMX.StdCtrls,
  FMX.Controls, FMX.Layouts, FMX.Memo, SyncObjs;

type
  TForm1 = class(TForm3D)

    Memo: TMemo;
    ProgressBar: TProgressBar;
    Layer3D1: TLayer3D;
    AniIndicator1: TAniIndicator;
    procedure Form3DCreate(Sender: TObject);
  private
    Fprogress: Integer;
    procedure Setprogress(const Value: Integer);
  public
    Lock : TCriticalSection;
    property progress : Integer read Fprogress write Setprogress;
  end;

  MyThread = class(TThread)

  protected
    Ip : Integer;
    procedure Execute; override;
    procedure UnserThread;
  public
    constructor Create(next : Integer);

  end;

var
  Form1: TForm1;
  thrd : MyThread;
  stack : TIdStack;

const
  NET : String = '172.17.4.';

implementation

{$R *.fmx}

procedure MyThread.UnserThread;
var
  str : String;
begin
  TIdStack.IncUsage;
  try
    str := Gstack.HostByAddress(NET + IntToStr(Ip));
  except on E: Exception do
    str := 'inexistent domain';
  end;
  TIdStack.DecUsage;

  Synchronize(
  procedure
  var
    I : Integer;
  begin
    I := 0;
    Form1.Lock.Enter;

      if Form1.Memo.Lines.Count <= 0 then
        Form1.Memo.Lines.Insert(0, '...' + Format('%3d',[Ip])+ ' - ' + str)
      else
      begin
        while ((Form1.Memo.Lines[I]) < ('...' + Format('%3d',[Ip])+ ' - ' + str)) or (I <= Form1.Memo.Lines.Count) do
          inc(I);
        Form1.Memo.Lines.Insert(I, '...' + Format('%3d',[Ip])+ ' - ' + str);
      end;

    Form1.Lock.Leave;

    Form1.ProgressBar.Value := Form1.ProgressBar.Value + 1;
    Form1.progress := Form1.Progress + 1;
  end);

end;

procedure TForm1.Form3DCreate(Sender: TObject);
var
  i : integer;
begin
  Lock := TCriticalSection.Create;

  for I := 1 to 254 do
    thrd := MyThread.Create(I);

  ProgressBar.Min := 1;
  ProgressBar.Max := 254;
  ProgressBar.Value := 1;
  progress := 1;

  //Memo.Lines.Add('Parse Net: ' + NET + '...');
end;

{ MyThread }

constructor MyThread.Create(next : Integer);
begin
  inherited Create;
  Ip := next;
end;

procedure MyThread.Execute;
begin
  inherited;
  UnserThread;
end;

procedure TForm1.Setprogress(const Value: Integer);
begin
  Fprogress := Value;
  if Fprogress = 254 then
    AniIndicator1.Enabled := False;
end;

end.
Sobald der erste Thread in der Zeile Form1.Lock.Enter; ankommt, wird ja für alle Anderen Threads der Zugriff/Weiterverarbeitung blockiert die an dieser Stelle ankommen, bis der schnellste/erste Thread mit der Ausführung bei Form1.Lock.Leave; ankommt. Synchronize brauche ich zusätzlich, um Änderungen an der Oberfläche/Hauptthread machen zu können.

Ich habe wohl einen Denkfehler/Missverständnis. Es ist das Erste mal, dass ich mit diesen beiden Klassen Arbeite.
Beim Debuggen jedenfalls läuft es garnicht wie ich mir das vorstelle. Er springt wild hin und her, was ja bei 200+ Threads nicht ganz unverständlich ist.
Ich denke trotzdem das jemand mit Erfahrung bestimmt einen guten Tipp hat. Zur Abwechslung mache ich es mir also mal leicht und frage gleich!

Grüße!
Die Leiter der Entwicklungsabteilung dreht total am Mausrad!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.016 Beiträge
 
Delphi 12 Athens
 
#2

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 14. Mai 2014, 18:22
Wenn dieses Form1.Lock.Enter; immer nur in dem Syncronize steht, bzw. immer nur im Hauptthread, dann kann da sowieso immer nur ein Thread vorbeikommen, da immer nur ein Thread gleichzeitig im Hauptthread arbeiten kann.

Die anderen Threads warten also schon beim Syncronize, bis der Thread zurückkommt und auch die VCL macht nichts, während ein Thread synchronisiert ist.


CriticalSections bringen nur etwas, wenn sie in verschiedenen Threads verwendet werden, um gemeinsame Resourcen gegenseitig abzusichern.
Genauso gut kann man alles in einen Thread synchronisieren (hier der Hauptthread) und ist damit auch abgesichert, da ja letztendlich nur der eine Thread darauf zugreift.



PS: Alles in dem Syncronize gehört doch zur Form? (wie man schön erkennen kann, da überall das Form1 davorgeschrieben werden mußte)
Also gehört das auch in eine Methode der Form und von dem/den Thread(s) auch ruft man dann diese Methode auf.
Fazit: Sobald du sehr oft auf solche globale Variablen zugreifen mußt, dann stimmt meistens irgendwas im Design nicht.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (14. Mai 2014 um 18:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 14. Mai 2014, 18:45
Nur so nebenbei:

Die ProgressBar sollte von 0..254 anzeigen und bei 0 starten, denn wenn 254 mal 1 um 1 erhöht wird, dann hat man 255
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 15. Mai 2014, 10:21
Da war auch noch ein Fehler in der While-Schleife.
Mein Vorschlag, ohne das ich jetzt getestet hab:
Delphi-Quellcode:
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.Variants, System.UITypes,
  System.Classes, FMX.Types, FMX.Graphics, FMX.Dialogs, FMX.Types3D, FMX.Forms,
  FMX.Forms3D, FMX.Controls3D, IdGlobal, IdStack, FMX.Layers3D, FMX.StdCtrls,
  FMX.Controls, FMX.Layouts, FMX.Memo, SyncObjs;

type
  TForm1 = class(TForm3D)
    Memo: TMemo;
    ProgressBar: TProgressBar;
    Layer3D1: TLayer3D;
    AniIndicator1: TAniIndicator;
    procedure Form3DCreate(Sender: TObject);
  private
    FProgress: Integer;
    procedure SetProgress(AValue: Integer);
    procedure DoOnThreadTerminate(Sender: TObject);
  public
    property Progress: Integer read FProgress write SetProgress;
  end;

  TMyThread = class(TThread)
  protected
    FIp: Integer;
    FStr: string;
    procedure Execute; override;
  public
    constructor Create(AIP: Integer; AFinishEvent: TNotifyEvent);
    property Ip: Integer read FIp;
    property Str: String read FStr;
  end;

var
  Form1: TForm1;
  stack : TIdStack;

const
  NET : String = '172.17.4.';

implementation

{$R *.fmx}

procedure TForm1.Form3DCreate(Sender: TObject);
var
  i : integer;
begin
  ProgressBar.Min := 0;
  ProgressBar.Max := 254;
  Progress := 0;

  for i := 1 to 254 do
    MyThread.Create(I, DoOnThreadTerminate);
end;

procedure TForm1.DoOnThreadTerminate(Sender: TObject);
var
  sIpStr: string;
  i: Integer;
begin
  with TMyThread(Sender) do
    sIpStr := Format('...%3d - %s', [Ip, Str]);

  i := 0;
  while (i < Memo.Lines.Count) and (Memo.Lines[i] < sIpStr) do
    Inc(i);

  Memo.Lines.Insert(i, sIpStr);

  Progress := Progress + 1;
end;

procedure TForm1.SetProgress(AValue: Integer);
begin
  FProgress := Value;
  ProgressBar.Value := AValue
  if FProgress = 254 then
    AniIndicator1.Enabled := False;
end;

{ MyThread }

constructor TMyThread.Create(AIp: Integer; AFinishEvent: TNotifyEvent);
begin
  inherited Create;
  FIp := AIp;
  OnTerminate := AFinishEvent;
end;

procedure TMyThread.Execute;
begin
  inherited;

  TIdStack.IncUsage;
  try
    FStr := Gstack.HostByAddress(NET + IntToStr(FIp));
  except on E: Exception do
    FStr := 'inexistent domain';
  end;
  TIdStack.DecUsage;
end;

end.
  Mit Zitat antworten Zitat
Benutzerbild von Jonas Shinaniganz
Jonas Shinaniganz

Registriert seit: 30. Aug 2011
249 Beiträge
 
Delphi XE5 Ultimate
 
#5

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 15. Mai 2014, 10:51
Delphi-Quellcode:
unit frmMain;

interface

uses
  System.SysUtils, System.Classes, FMX.Forms3D, IdGlobal, IdStack,
  FMX.Layers3D, FMX.StdCtrls, FMX.Layouts, FMX.Memo, FMX.Edit, FMX.Controls,
  FMX.Controls3D, FMX.Types;

type
  TMainForm = class(TForm3D)
    Memo: TMemo;
    ProgressBar: TProgressBar;
    Layer3D1: TLayer3D;
    AniIndicator1: TAniIndicator;
    NumberBox1: TNumberBox;
    Label1: TLabel;
    NumberBox2: TNumberBox;
    NumberBox3: TNumberBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    Output : TStringlist;
    FProgress : Integer;
    procedure AddToMemo(Ip : Integer; Str : String);
    procedure Setprogress(const Value: Integer);
  public
    property Progress : Integer read FProgress write SetProgress;
  end;

  TLookupThread = class(TThread)
  protected
    Ip : Integer;
    procedure Execute; override;
  public
    constructor Create(Next : Integer);
  end;

var
  MainForm : TMainForm;
  NET : String = '172.17.4.';

implementation

{$R *.fmx}

procedure TMainForm.AddToMemo(Ip : Integer; Str : String);
begin
  Output.Add('...' + Format('%3d',[Ip])+ ' - ' + str);
  Progress := Progress + 1;
end;

procedure TMainForm.Button1Click(Sender: TObject);
var
  i : integer;
  thrd : TLookupThread;
begin
  Output := TStringList.Create;

  NET := NumberBox1.Value.ToString + '.' + NumberBox2.Value.ToString + '.' + NumberBox3.Value.ToString + '.';

  for I := 1 to 254 do
    thrd := TLookupThread.Create(I);

  ProgressBar.Min := 0;
  ProgressBar.Max := 253;
  Progress := 0;

  AniIndicator1.Enabled := true;
  AniIndicator1.Visible := true;
end;

constructor TLookupThread.Create(Next : Integer);
begin
  inherited Create;
  Ip := Next;
end;

procedure TLookupThread.Execute;
var
  str : String;
begin
  inherited;
  TIdStack.IncUsage;
  try
    str := Gstack.HostByAddress(NET + IntToStr(Ip));
  except on E: Exception do
    str := 'inexistent domain';
  end;
  TIdStack.DecUsage;

  Synchronize(
  procedure
  begin
    MainForm.AddToMemo(Ip, Str);
  end);

  Self.Free;
end;

procedure TMainForm.Setprogress(const Value : Integer);
begin
  FProgress := Value;
  ProgressBar.Value := FProgress;
  if FProgress = 254 then
  begin
    AniIndicator1.Enabled := False;
    AniIndicator1.Visible := False;
    Output.Sort;
    Output.Insert(0, 'parse net: ' + NET + '...');
    Memo.Lines.Assign(Output);
    Output.Free;
  end;
end;

end.
Naja ich habe es so angepasst. Programm gibt's im Anhang, leicht erweitert.
Die While-Schleife macht ja einen Insertionsort... Das war auch vorher der Haken, habe es dann so ähnlich korrigiert. Danach fand ich das häufige hinzufügen von Lines zum Memo aber nicht mehr schön. Nutze letztlich eine TStringlist. Für mich ist das jetzt auch schon wieder abgehakt Danke an euch.

Edit:
Warum gibt es eigentlich keine Warnung das
Zitat:
stack : TIdStack;
nie benutzt wird? @Blup Das mit dem Event ist natürlich schöner designed.
Angehängte Dateien
Dateityp: rar AreaLookup.rar (1,30 MB, 8x aufgerufen)
Die Leiter der Entwicklungsabteilung dreht total am Mausrad!

Geändert von Jonas Shinaniganz (15. Mai 2014 um 10:55 Uhr)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 15. Mai 2014, 12:42
Für globale Variablen kann es so eine Warnung nicht geben.
Der Compiler weis nicht ob diese Unit eventuell auch in anderen Projekten verwendet wird, die genau diese Variable benötigen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.016 Beiträge
 
Delphi 12 Athens
 
#7

AW: TThread Syncronise & TCriticalSection.Enter

  Alt 15. Mai 2014, 12:52
Globale Variablen sind halt böse.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz