Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Parameter an Thread übergeben (https://www.delphipraxis.net/176476-parameter-thread-uebergeben.html)

IMPEGA 8. Sep 2013 09:53

Delphi-Version: 5

Parameter an Thread übergeben
 
Hi Leute.
Ich habe mich ein wenig in Threading eingearbeitet, nun habe ich eine Technische Frage.
Wie macht man es richtig mit den Parametern.
Hier zwei Beispiele, beide funktionieren, meine Frage dazu, was davon ist richtig, bzw. besser.
Ich poste nur das relevante.

Erster Beispiel. Die Variable wird als Public deklariert und in Unit1 einfach gesetzt.
Delphi-Quellcode:
//Unit Thread

type
  TMyThread = class(TThread)
  private
    Wert       : String; // Werte der nur im Thread benutzt wird
    Bezeichnung : String; // Werte der nur im Thread benutzt wird
    procedure UpdateStaus;
    procedure Finished;
    procedure Abort;
  public
    SSL      : Boolean; // Werte der von der UNIT1 übernommen wird
  protected
    procedure Execute; override;
  end;

implementation
...
...

//in der UNIT1
...
...
  Thread                := TImageShackThread.Create(True);
  Thread.SSL            := False;
  Thread.FreeOnTerminate := True;
  Thread.Resume;
...
Oder eine zweite Methode

Delphi-Quellcode:
//Und UNIT Thread
type
  TMyThread = class(TThread)
  private
    Wert       : String; // Werte der nur im Thread benutzt wird
    Bezeichnung : String; // Werte der nur im Thread benutzt wird
    SSL        : Boolean;// Werte der nur im Thread benutzt wird
    procedure UpdateStaus;
    procedure Finished;
    procedure Abort;
  public
    procedure SetSSL(ThreadSSL : Boolean); // Procedure die den Wert übernimmt
  protected
    procedure Execute; override;
  end;

implementation
...
...
procedure TMyThread.SetSSL(ThreadSSL : Boolean); // Damit hab ich mein Wert im Thread zur Verfügung
begin
  SSL := ThreadSSL;
end;
...
...
...

//und in der UNIT1
...
...
  Thread := TMyThread.Create(True);
  Thread.SetSSL(False);
  Thread.FreeOnTerminate := True;
  Thread.Resume;
...

Bjoerk 8. Sep 2013 10:07

AW: Parameter an Thread übergeben
 
Dafür gibt's properties.

Delphi-Quellcode:
  private
    FSSL: boolean;
  public
    property SSL: boolean read FSSL write FSSL;
Innerhalb von TMyThread dann mit FSSL arbeiten.

// Edit: wenn man das write weglässt ist die Variable ReadOnly,
wenn man read weglässt WriteOnly.

IMPEGA 8. Sep 2013 10:15

AW: Parameter an Thread übergeben
 
Kannst mir noch bitte sagen wie ich es dann von der Unit1 übergeben kann?
Ich lerne es erst.

Mir ist noch eine Frage eingefallen.
Irgendwo habe ich den Satz gelesen "alle Zugriffe auf nicht threadsichere VCL-Dinge über Synchronize erledigen"
Wie weit ist es wichtig?
Ist es so schlecht vom Thread aus auf zB. Tform1.Laqbel1 zu zugreifen?

OlafSt 8. Sep 2013 10:36

AW: Parameter an Thread übergeben
 
Das Ding mit den Properties hast du noch nicht ganz verstanden ;)


Delphi-Quellcode:
TMyThread = class(TThread);
private
    FSSL: boolean;
public
    property SSL: boolean read FSSL write FSSL;
end;
SSL kann nun wie eine public-Variable angesprochen werden:
Delphi-Quellcode:
...
Thread := TMyThread.Create(True);
Thread.SSL := False;
...
Zitat:

Ist es so schlecht vom Thread aus auf zB. Tform1.Laqbel1 zu zugreifen?
Ja. Ist es. Glaub es uns, wir leben damit schon über eine Dekade lang.

Bjoerk 8. Sep 2013 10:41

AW: Parameter an Thread übergeben
 
Zitat:

Zitat von IMPEGA (Beitrag 1227574)
Kannst mir noch bitte sagen wie ich es dann von der Unit1 übergeben kann? Ich lerne es erst.

Delphi-Quellcode:
  MyThread := TMyThread.Create(True);
  MyThread.SSL := False;
Zitat:

Zitat von IMPEGA (Beitrag 1227574)
Mir ist noch eine Frage eingefallen. Irgendwo habe ich den Satz gelesen "alle Zugriffe auf nicht threadsichere VCL-Dinge über Synchronize erledigen"
Wie weit ist es wichtig? Ist es so schlecht vom Thread aus auf zB. Tform1.Laqbel1 zu zugreifen?

Ja. Und das am besten mit Events. Wird aber etwas kompliziert, wenn du nicht weißt, was ein Event ist? Und "Uses unit1" hat in der ThreadUnit nichts verloren.

IMPEGA 8. Sep 2013 11:21

AW: Parameter an Thread übergeben
 
Danke Euch Jungs. Damit habt Ihr mir gut geholfen.
Das mit Propertys habe ich doch verstanden, sogar darüber gelesen, mir kam es aber so vor als ob es nicht wichtig wäre.
Propertys muss ich mir noch genaue durchlesen. Gar keine Frage.
Das man die so ansprechen kann, habe ich eigentlich gewusst, wollte aber nicht wie ein Trottel da stehen wenn es nicht so wäre, also lieber nachfragen.

Eine Frage hätte ich aber noch.
Wo ist eigentlich der Unterschied zwischen der Methode mit procedure und der Methode mit property.
Es wird doch genauso angewandt.
Sorry für die Neugier, mir geht es mehr darum es zu verstehen wieso und warum. Hinkriegen kann ich es schon, darum geht es aber nicht alleine.
Klar ist der Code kleiner, es muss aber noch mehr sein als nur das.


TMyThread = class(TThread);
private
FSSL: boolean;
public
property SSL: boolean read FSSL write FSSL;
end;




TMyThread = class(TThread);
private
FSSL: boolean;
public
procedure SetSSL(ThreadSSL : Boolean);
end;
implementation
...
...
procedure TMyThread.SetSSL(ThreadSSL : Boolean);
begin
SSL := ThreadSSL;
end;


Zitat:

Ja. Und das am besten mit Events. Wird aber etwas kompliziert, wenn du nicht weißt, was ein Event ist? Und "Uses unit1" hat in der ThreadUnit nichts verloren.
Dazu habe ich ein Beispiel. Kriege es zwar nachgebaut. Eigentlich wenn ich lange genug mir den Code anschaue, verstehe ich es auch, aus dem Kopf würde ich es aber nie im Leben coden können. Egal, ich mache ganz langsam. Step by step.

mjustin 8. Sep 2013 12:06

AW: Parameter an Thread übergeben
 
Parameter werden in der Regel nur einmalig beim Start an den Thread übergeben. Daher ist oft der Konstruktor die einfachste Stelle, alle notwendigen Daten / Parameter in interne (private) Properties des Threads zu übergeben.

Alles was während der Ausführungszeit des Threads (während der Laufzeit der Execute Methode) übergeben oder ausgelesen wird, wie zum Beispiel über Properties, ist erst mal nicht thread safe - man muss diese dann entsprechend absichern, zum Beispiel über Critical Sections.

IMPEGA 8. Sep 2013 12:16

AW: Parameter an Thread übergeben
 
Eine wichtige Frage habe ich noch bevor es weiter gehen kann.

Zitat:

Und "Uses unit1" hat in der ThreadUnit nichts verloren.
Nun, wie gebe ich die Werte wieder zurück ?
In meinem Fall ist es eine
- Stringlist, die im Thread bearbeitet und zurück gegeben werden soll.
- Ein String, der in eine ListBox einzufügen ist
- Ein Integer der sich immer ändert. Sprich ist starte mehrere Threads (ohne Event) einfach
Delphi-Quellcode:
  for i := 1 to 1 do
    begin
      Thread[i] := TMyThread.Create(True);
      Thread[i].Liste := Liste;
      Thread[i].FreeOnTerminate := True;
      Thread[i].Resume;
    end;
Nun, wird etwas im Thread gemacht und mein Progressbar muss aktualisiert werden.
Wie gibt man so was zurück ohne
uses Unit1 im Thread ?

Etwa über property , aber in andere Richtung? --> wohl kaum.

jaenicke 8. Sep 2013 13:22

AW: Parameter an Thread übergeben
 
FreeOnTerminate und Resume ist keine gute Idee, da der Thread dann evtl. so schnell weg ist, dass es Zugriffsprobleme gibt.
Und einen Thread, der auf FreeOnTerminate gesetzt ist, in einer Liste zu speichern ist ein No-Go, denn du weißt nie, wann du noch darauf zugreifen kannst.

Du musst dich entscheiden:
Möchtest du von außen deine TThread-Objekte in einer Liste haben, dann musst du diese auch von außen am Ende freigeben. Oder du benutzt FreeOnTerminate, überlässt die Threads dann aber auch sich selbst.

Zudem ist es auch viel einfacher, wenn du deine Liste gleich im Konstruktor übergibst. Zur Aktualisierung der Progressbar gibt es mehrere Möglichkeiten, eine ist mit Snychronize zu arbeiten, aber das bremst den Thread aus. Alternativ schick einfach mit PostMessage eine Message an das Hauptfenster, dann macht Windows die Synchronisation für dich.

IMPEGA 8. Sep 2013 13:57

AW: Parameter an Thread übergeben
 
Zitat:

Zudem ist es auch viel einfacher, wenn du deine Liste gleich im Konstruktor übergibst.
So weit bin ich noch nicht. Wie schon gesagt Step by Step.

Zitat:

Alternativ schick einfach mit PostMessage eine Message an das Hauptfenster, dann macht Windows die Synchronisation für dich.
Damit komme ich ohne Beispiel nicht klar. Wäre aber interessante Sache.

Bis jetzt Alles was ich gelesen habe arbeitete mit Synchronize. Ob es nun etwas langsamer ist , ist für mich nicht wirklich wichtig, ich versuche halt nach und nach die Sache zu verstehen. Allerdings bei Synchronize kann man kaum auf Uses UNIT1 verzichten.
Ganz so einfach ist das doch nicht. Leider. Ich versuche wie gesagt nach und nach etwas mehr zu verstehen.

Bjoerk 8. Sep 2013 14:25

AW: Parameter an Thread übergeben
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von IMPEGA (Beitrag 1227587)
Etwa über property , aber in andere Richtung? --> wohl kaum.

Eben, dann bekommst du eine Zirkularität rein, auch wenn der Compiler das unterhalb von implementation akzeptieren würde.

Kleines ThreadBeispiel mit Events:

IMPEGA 8. Sep 2013 14:44

AW: Parameter an Thread übergeben
 
Danke dir. Das muss ich zuerst durch kauen.
Es bringt mich aber schon weiter.

EDIT:
OK, soweit habe ich es verstanden.
Hier passiert nämlich folgendes, wir starten ein Thread erhalten die Information, tragen die in die memo1 ein.
So lange bis wir es terminieren oder ThreadActivate := false;

Nun, gut und schön, ich möchte aber die Möglichkeit haben die Anzahl der Threads zu bestimmen.
Und zwar so dass zB. Meine Liste 10 Einheiten hat, ich die mit 5 Threads abarbeiten möchte.
In Forum habe ich schon etwas gefunden, Threadpool wäre interessant.
Es ist aber noch etwas zu schwer für mich.


@Bjoerk
Dein Beispiel kann ich sehr gut verstehen, kann man das auch so irgendwie realisieren dass man mehrere Threads startet? Ich meine so dass der nächste Thread immer den Nächsten Job übernimmt und nicht so dass man mehrere Threads parallel startet die das Gleiche tun.
Das was ich hier in Forum gefunden habe übersteigt meine Möglichkeiten.(Leider)
Ich versuche es zwar Alles zu verstehen, ganz so einfach ist es aber nicht.

Gutelo 2. Okt 2013 07:56

AW: Parameter an Thread übergeben
 
Bezueglich dieses Themas habe ich noch eine weitere Frage:

Ich habe eine Variable folgenden Typs, die im Hauptprogramm global definiert ist:

type TMyVar = record
a : String;
b : String;
c : Array of Array of integer;
d : Integer;
e : Array[1..6,1..6] of double;
end;

var MyVar : TMyVar;


Weder das Uebergeben des Wertes mittels einer Threadprozedur folgender Form

procedure MyThread.setMyVar(var MV : TMyVar);
begin
FMyVar := MV;
end;

(also via MyThread.setMyVar(MyVar);) noch die Uebergabe mittels 'property ...' bewirken, dass Aenderungen die der Thread an dem Record durchfuehrt (d.h., an FMyVar) , nach Beendigung des Threads auch and der Originalvariablen MyVar geschehen sind. Wie kann ich es erreichen dass die vom Thread gemachten Aenderungen am Record auch in MyVar geschehen?

Gruesse

Gutelo

DeddyH 2. Okt 2013 08:31

AW: Parameter an Thread übergeben
 
Und wenn Du einen Pointer auf den Record an den Thread übergibst und innerhalb des Threads auf diesen zugreifst?

Gutelo 2. Okt 2013 08:52

AW: Parameter an Thread übergeben
 
Ich habe gerade nochmal den Informationsfluss von Mainform zu Thread ueberprueft. Der Inhalt des Records im Mainform kommt definitv im Thread an. Kann es sein dass Uebergaben bei Threads nicht per call-by-reference geschehen? Dann wunder ich mich aber, dass bei uebergebenen VCL Komponenten ein synchronize moeglich ist.

Blup 2. Okt 2013 08:59

AW: Parameter an Thread übergeben
 
Objekte, also auch VCL-Komponenten, werden immer als Referenz übergeben und in Referenzvariablen gespeichert.
Deine interne Record-Variable ist aber keine Referenz, sondern eine Kopie.
Delphi-Quellcode:
type
  PMyVar = ^TMyVar;

  TMyThread = class(TThread)
  private
    FExtVar: PMyVar;
    FMyVar: TMyVar;
    CopyToExtVar;
    DoOnTerminate; override;
  public
    {darf nur im constructor oder vor dem Resume aus dem Hauptthread aufgerufen werden}
    InitMyVar(var MV: TMyVar);
  end;

procedure TMyThread.InitMyVar(var MV: TMyVar);
begin
  {Verweis auf externe Variable}
  FExtVar := @MV;
  {Kopie der externen Variable}
  FMyVar := MV;
end;

procedure TMyThread.DoOnTerminate;
begin
  {wird beim Beenden im Thread aufgerufen}
  if Assigned(FExtVar) then
    Synchronize(CopyToExtVar);
  inherited;
end;

procedure TMyThread.CopyToExtVar;
begin
  {interne Variable in die externe Variable kopieren}
  if Assigned(FExtVar) then
    FExtVar^ := FMyVar;
end;

DeddyH 2. Okt 2013 09:04

AW: Parameter an Thread übergeben
 
IIRC wird durch die Zuweisung des Parameters an das private Feld eine Kopie des Records erzeugt, da nützt auch die "var"-Angabe nichts. Übergibt man hingegen den Pointer, arbeitet man tatsächlich mit dem Original. Objektinstanzen sind übrigens intern auch Pointer, daher funktioniert das damit.

Gutelo 2. Okt 2013 09:08

AW: Parameter an Thread übergeben
 
hmm genau das scheint der Fall zu sein. Records werden anscheinend nur call-by-value an Threads uebergeben. Siehe folgende Diskussion:

http://stackoverflow.com/questions/9...y-of-an-object

Der letzte Vorschlag in der Liste entspricht der Idee von DeddyH einen Pointer auf das Array zu uebergeben. Ganz wohl ist mir dabei nicht, da ich nicht sicher bin ob das Terminieren des Threads ein moegliches Problem darstellen koennte.

DeddyH 2. Okt 2013 09:35

AW: Parameter an Thread übergeben
 
Solange Du nicht auf die Idee kommst, beim Terminieren des Threads ein Dispose auf den Pointer loszulassen, wüsste ich nicht, was für Probleme auftreten sollten.

Blup 2. Okt 2013 09:42

AW: Parameter an Thread übergeben
 
Zitat:

Zitat von DeddyH (Beitrag 1230581)
Objektinstanzen sind übrigens intern auch Pointer, daher funktioniert das damit.

Richtiger:
Objektvariablen sind Pointer die auf eine Instanz der Klasse (oder einer abegleiteten Klasse) verweisen.
Bei der Zuweisung einer Objektvariablen wird nicht die Instanz kopiert, sondern nur deren Adresse weitergegeben.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz