Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Event in Thread (https://www.delphipraxis.net/191994-event-thread.html)

Hobbycoder 11. Mär 2017 14:40

Event in Thread
 
Hi,

ich stelle mir grad folgende Frage: Ich könnte ja in einem Thread auch ein Event hinzufügen. Als Beispiel so
Delphi-Quellcode:
type
  TOnSendAnMain=procedure(Sender: TObject; Irgendwas: string) of object;

  TMyThread=class(TThread)
  private
    FOnSendAnMain: TOnSendAnMain;
    procedure DoSendAnMain(Irgendwas: string);
  published
    property OnSendAnMain: TOnSendAnMain read FOnSendAnMain write FOnSendAnMain;
  public
    ...
  end;
wie müsste die procedure DoSendAnMain aussehen?

So
Delphi-Quellcode:
procedure TMyThead.DoSendAnMain(Irgendwas: string);
begin
  if Assigned(FOnSendAnMain) then
    FOnSendAnMain(self, Irgendwas);
end;
oder so:
Delphi-Quellcode:
procedure TMyThead.DoSendAnMain(Irgendwas: string);
begin
  if Assigned(FOnSendAnMain) then
    Synchronize(FOnSendAnMain(self, Irgendwas));
end;
Da sich hinter FOnSendAnMain ja eine Procedure aus einem anderen Thread verbirgt (z.B. Hauptthread) müsste der Zugriff ja Synchron erfolgern, oder sehe ich das falsch, oder ist das hier nicht notwendig?

Gruß Hobbycoder

stahli 11. Mär 2017 15:14

AW: Event in Thread
 
Über Synchronize ist das korrekt. Sofern die Methode nicht im Mainthread definiert ist müsste man statt Synchronize z.B. CriticalSections verwenden.

Die Methode solltest Du wenn möglich über den Constructor übergeben.
Andernfalls íst es denkbar, dass es bei einer späteren Zuweisung zu Konflikten kommen kann, wenn eine alte Methode gerade ausgeführt wird während eine neue zugewiesen wird. Dann müsste man die Zugriffe nochmal z.B. über eine CriticalSection absichern.

Hobbycoder 11. Mär 2017 15:21

AW: Event in Thread
 
Ich mache das bisher so, dass ich den Thread Suspended starte, dann die Methoden zuweise und mit Resume dann losmarschieren lasse.

Wie würde denn so ein Create und dann die Zuweisung aussehen? Es wird ja nur ein Pointer übergeben.

stahli 11. Mär 2017 15:56

AW: Event in Thread
 
Delphi-Quellcode:
  TMyThread=class(TThread)
   private
     fOnSendAnMain: TOnSendAnMain;
     procedure DoSendAnMain(Irgendwas: string);
   public
     constructor Create(aOnSendAnMain: TOnSendAnMain); overload;
   end;

constructor TMyThread.Create(aOnSendAnMain: TOnSendAnMain);
begin
  fOnSendAnMain := aOnSendAnMain;
  Create(False);
end;

Hobbycoder 11. Mär 2017 15:58

AW: Event in Thread
 
Ja, klar logisch.

Manchmal denke ich etwas zu kompliziert ;-)

jfheins 11. Mär 2017 15:58

AW: Event in Thread
 
Das ist doch Jacke wie Hose.

Will sagen: Du kannst beides problemlos machen. Die Variante mit Synchronize hält den Thread halt mehr auf.

Dafür solltest bei dieser Variante:
Delphi-Quellcode:
procedure TMyThead.DoSendAnMain(Irgendwas: string);
begin
  if Assigned(FOnSendAnMain) then
    FOnSendAnMain(self, Irgendwas);
end;
Dokumentieren, dass das Event in einem separaten Thread aufgerufen wird und eventuelle Interaktionen mit der GUI besonders behandelt werden müssen.
Je nachdem wie du das Event auslöst, muss ggf. der Empfängercode anders geschrieben werden. Du hast also die Wahl zwischen Idiotensicher (Synchronize im Thread) oder Performance.

Falls das Event ausschließlich für GUI Darstellung genutzt wird, ist es komplett egal, da ist Variante 2 (Synchronize im Thread) vll. intuitiver.

HolgerX 11. Mär 2017 16:43

AW: Event in Thread
 
Hmm..


Ich würde das wie schon geschrieben über den Contructor lösen:

Delphi-Quellcode:
type
  TOnSendAnMain=procedure(Sender: TObject; Irgendwas: string) of object;

  TMyThread=class(TThread)
  private
    FNeedSync : boolean;
    FIrgendwas: string;
    FOnSendAnMain: TOnSendAnMain;
    procedure DoSendAnMain(Irgendwas: string);
    procedure DoSendAnMainSyc;
  protected
    procedure Execute; override;
    property OnSendAnMain: TOnSendAnMain read FOnSendAnMain write FOnSendAnMain;
    property NeedSync : boolean read FNeedSync write FNeedSync;
  public
    constructor create(AOnSendAnMain: TOnSendAnMain;ANeedSync : boolean);reintroduce;
  end;

implementation

{ TMyThread }

constructor TMyThread.create(AOnSendAnMain: TOnSendAnMain;
  ANeedSync: boolean);
begin
  FIrgendwas := '';
  FOnSendAnMain:= AOnSendAnMain;
  FNeedSync := ANeedSync;
  inherited create(false);
end;

procedure TMyThread.DoSendAnMain(Irgendwas: string);
begin
  FIrgendwas := Irgendwas;
  if FNeedSync then begin
    Synchronize(DoSendAnMainSyc);
  end else
    DoSendAnMainSyc;
end;

procedure TMyThread.DoSendAnMainSyc;
begin
  if Assigned(FOnSendAnMain) then FOnSendAnMain(self, FIrgendwas);
end;

procedure TMyThread.Execute;
begin
  DoSendAnMain('Bla bla bla');
end;

Dadurch kann beim erstellen des Thread-Objectes entschieden werden, ob ein Sync notwendig ist, oder nicht...

Zacherl 11. Mär 2017 19:19

AW: Event in Thread
 
Meiner Erfahrung nach ist es in 99% der Fälle unerwünscht, dass der Thread ein komplettes Event intern schon synchronisiert.

Wenn du das Event einfach nur ganz normal auslöst und dokumentierst, dass es im Kontext eines seperaten Threads aufgerufen wird, hat der Benutzer sehr viel mehr Möglichkeiten für spezifische Optimierungen. Wenn z.b. ClientSocket in einem Thread auf eingehende Daten wartet und dann ein Event zur Verarbeitung auslöst, ist in den meisten Fällen ja gar keine Synchronisierung mit dem Main-Thread erforderlich bzw. nur für ein kurzes GUI Update nach der eigentlichen Verarbeitung.

himitsu 11. Mär 2017 19:54

AW: Event in Thread
 
Alternativ diese Synchronisierung per Option (Property) aktivierbar/deaktivierbar.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:51 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