Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Threadklasse mit Event aktualisiert nicht (https://www.delphipraxis.net/215729-threadklasse-mit-event-aktualisiert-nicht.html)

Inspur1 28. Aug 2024 04:17

Threadklasse mit Event aktualisiert nicht
 
Greetings!

Ich entwickel in FreePascal eine Threadklasse mit einem Event und einigen Eigenschaften.
Um das Problem besser zu erklären, habe ich das Beispiel kompromiert.

Delphi-Quellcode:
unit uTest;

interface

uses Classes;

type
  TTestThread = class(TThread)
  private
    FTestProperty: string;
    FOnTest: TNotifyEvent;
  protected
    procedure DoTest; virtual;
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    property TestProperty: string read FTestProperty write FTestProperty;
    property OnTest: TNotifyEvent read FOnTest write FOnTest;
  end;

implementation

constructor TTestThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FTestProperty := 'default';
end;

destructor TTestThread.Destroy;
begin
  inherited;
end;

procedure TTestThread.DoTest;
begin
  if not Assigned(FOnTest) then
    FOnTest(self);
end;

procedure TTestThread.Execute;
begin
  DoTest;
end;


end.



// Call

private
  FTest: TTestThread;
  procedure MyTest(Sender: TObject);

procedure TForm1.MyTest(Sender: TObject);
begin
  FTest.TestProperty := '>>> Test2 <<<';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FTest := TTestThread.Create(false);
  FTest.FreeOnTerminate := false;
  FTest.OnTest := MyTest;
  FTest.Resume;
  Caption := FTest.TestProperty;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Assigned(FTest) then
    FTest.Free;
end;
Ich will im Event die Eigenschaft ändern aber es bleibt bei "default".
Wie mache ich das richtig?

jaenicke 28. Aug 2024 05:43

AW: Threadklasse mit Event aktualisiert nicht
 
Du liest die Eigenschaft direkt nach dem Resume aus. Ein Thread läuft aber eben parallel. Daher wird das Event erst danach ausgeführt.

Dass das Event ausgeführt wird, würdest du mit einem Haltepunkt sofort sehen.

Eine Aktualisierung müsste daher auch dort im Event angestoßen werden, was in dem Beispiel natürlich wenig Sinn macht. Die Konstruktion macht eher Sinn, wenn der Thread den Wert setzt und im Event dann die Aktualisierung angestoßen wird.

Was möchtest du denn erreichen?

Olli73 28. Aug 2024 06:28

AW: Threadklasse mit Event aktualisiert nicht
 
Ein "Not" zu viel:

Delphi-Quellcode:
if not Assigned(FOnTest) then
    FOnTest(self);

Inspur1 28. Aug 2024 06:29

AW: Threadklasse mit Event aktualisiert nicht
 
Ich möchte mehrere HTML auslesen, im Event möchte ich festlegen wonach gesucht wird und die Ergebnisse den Eigenschaften übergeben.

Rollo62 28. Aug 2024 07:19

AW: Threadklasse mit Event aktualisiert nicht
 
Du nutzt FTestProperty innerhalb des Threads und außerhalb im UI Thread, ohne irgendeine Art der Synchronisation,
wenn ich das richtig sehe.

Auf jeden Fall sollte man den Zugriff im UI Thread dann synchronisieren, aber die Frage siehe oben, was willst Du erreichen?

Blup 28. Aug 2024 09:49

AW: Threadklasse mit Event aktualisiert nicht
 
vorgeschlagene Änderungen:
Delphi-Quellcode:
uses Classes, System.SyncObjs;

type
  TTestThread = class(TThread)
  private
    FTestProperty: string;
    FOnTest: TNotifyEvent;
    function GetTestProperty: string;
    procedure SetTestProperty(const AValue: string);
  protected
    FCS: TCriticalSection;
    procedure DoTest; virtual;
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    {kann aus einem anderen Thread gelesen und verändert werden}
    property TestProperty: string read GetTestProperty write SetTestProperty;
    {wird im Hauptthread aufgerufen (ermöglicht Zugriff auf die VCL)}
    property OnTest: TNotifyEvent read FOnTest write FOnTest;
  end;

implementation

procedure TTestThread.DoTest;
begin
  if Assigned(FOnTest) then // ???: if not Assigned(FOnTest) then
    FOnTest(self);
end;

constructor TTestThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FTestProperty := 'default';
  FCS := TCriticalSection.Create;
end;

destructor TTestThread.Destroy;
begin
  FCS.Free;
  inherited;
end;

procedure TTestThread.Execute;
begin
  Synchronize(DoTest);
end;

function TTestThread.GetTestProperty: string;
begin
  FCS.Enter;
  try
    Result := FTestProperty;
  finally
    FCS.Leave;
  end;
end;

procedure TTestThread.SetTestProperty(const AValue: string);
begin
  FCS.Enter;
  try
    FTestProperty := AValue;
  finally
    FCS.Leave;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FTest := TTestThread.Create(false);
  FTest.FreeOnTerminate := false;
  FTest.OnTest := MyTest;
  FTest.Resume;
  repeat
    CheckSynchronize(10);
  until FTest.Terminated;
  Caption := FTest.TestProperty;
  FTest.Free;
end;

jaenicke 28. Aug 2024 12:12

AW: Threadklasse mit Event aktualisiert nicht
 
Zitat:

Zitat von Olli73 (Beitrag 1540293)
Ein "Not" zu viel:

Delphi-Quellcode:
if not Assigned(FOnTest) then
    FOnTest(self);

Oh ja, das habe ich am Handy glatt übersehen.

Rollo62 28. Aug 2024 15:09

AW: Threadklasse mit Event aktualisiert nicht
 
TL;DR;

Delphi-Quellcode:
procedure TTestThread.Execute;
begin
  Synchronize(DoTest);
end;
Das macht nicht so viel Sinn, denn damit läuft ja dein zu "threadender" Code wieder im Main UI-Thread, wenn ich das richtig interpretiere.
Es sollte doch nur das Ergebnis synchronisiert werden.

himitsu 28. Aug 2024 15:41

AW: Threadklasse mit Event aktualisiert nicht
 
DoTest ist quasi die Methode, welche OnTest auslöst, womit dieses Synchronize schon stimmt. (die Namensgebung ist in der VCL Vielerorts genauso)


Am Ende klingt es so, als wenn der "eigentliche" Code noch viel mehr macht, wie z.B. vorher scheinbar eine Datei runterladen. (natürlich außerhalb des Synchronize)




Prinzipiell sind LongStrings (String/AnsiString/UnicodeString) und ihre Referenzzählung per se thread-save.

Funktional quasi so, als wenn man einen Integer/Boolean/LongBool/Pointer mit den Interlocked-, bzw. Atomic-Funktionen schreibend (Inc/Dec) und kopierend behandelt.

Rollo62 28. Aug 2024 16:00

AW: Threadklasse mit Event aktualisiert nicht
 
Zitat:

Zitat von himitsu (Beitrag 1540325)
DoTest ist quasi die Methode, welche OnTest auslöst, womit dieses Synchronize schon stimmt. (die Namensgebung ist in der VCL Vielerorts genauso)

Delphi-Quellcode:
FTest.OnTest := [B]MyTest[/B];
Das klingt für mich eigentlich danach, dass OnTest die harte Threadarbeit macht ...
Kann mich aber irren

Jedenfalls sieht das hier nicht so aus, als würde der Thread überhaupt irgendwie zum Tragen kommen.
Der Button hängt doch, bis der Thread terminiert ist.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  FTest := TTestThread.Create(false);
  FTest.FreeOnTerminate := false;
  FTest.OnTest := MyTest;
  FTest.Resume;
  repeat
    CheckSynchronize(10);
  until FTest.Terminated;
  Caption := FTest.TestProperty;
  FTest.Free;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:34 Uhr.
Seite 1 von 2  1 2      

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