Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Events in einem Thread (https://www.delphipraxis.net/151735-events-einem-thread.html)

ThorvdA 30. Mai 2010 13:17


Events in einem Thread
 
Hallo zusammen,

es geht darum Events von Komponenten in einem Thread aufzurufen.
Also der Thread erstellt sich (beispielsweise) einen Timer in Create und setzt das Event auf eine eigene Prozedur.
Hier die wichtigsten Zeilen:

Delphi-Quellcode:
type TMeinthread = class(TThread)
                     private
                       Timer : TTimer;
                       procedure TimerEvent(Sender : TObject);
                     public
                       constructor Create(CreateSuspended : Boolean); override;
                       procedure Execute; override;
                     end;

implementation

constructor TMeinthread.Create(CreateSuspended : Boolean);
begin
  inherited;
  Timer:=TTimer.Create(nil);
  Timer.OnTimer=TimerEvent;
end;

procedure TMeinthread.Execute;
begin
  while not Terminated do
    Sleep(100); // irgendwas eben
end;

procedure TMeinthread.TimerEvent(Sender : TObject);
begin
  Sleep(500); // noch irgendwas
end;
Wie ich natürlich bemerken musste läuft das TimerEvent innerhalb meines Hauptthreads ab und blockiert mein Formular.
Was kann ich dagegen tun? Das ganze ist nur Beispielhaft, ich stehe häufiger vor dieser Art von Problem.

Grüße!

wicht 30. Mai 2010 13:51

Re: Events in einem Thread
 
Delphi-Quellcode:
procedure TMeinthread.Execute;
var
  i: Integer;
begin
  i := 0;
  while not Terminated do
  begin
    // irgendwas
    if i = 5 then
    begin
      // noch irgendwas
      i := 0;
    end;
    Sleep(100);
    Inc(i);
  end;
end;

sirius 30. Mai 2010 14:13

Re: Events in einem Thread
 
Du darfst die Komponenten (hier timer) erst in Execute erstellen. Allerdings brauchst du hier eine Hier im Forum suchenMessageschleife

ThorvdA 30. Mai 2010 14:53

Re: Events in einem Thread
 
Danke,
echt schnelle Antworten hier :)

also den Timer in Execute zu erstellen ist kein Problem.
Verstehe ich das bei den Messageschleifen richtig dass es um Windowsmessages geht?
Generiert der Timer eine bestimmte Message die ich abfangen muss/kann (die WM_TIMER)?
Wenn das so ist, was tue ich dann bei eigenen Objekten die nicht unbedingt mit Windowsmessages arbeiten?

Edit: @wicht
Das hilft mir leider nicht weiter. Der Timer war nur Beispielhaft.

sirius 30. Mai 2010 15:07

Re: Events in einem Thread
 
Ja, der Timer arbeitet mit Windowsmessages (ist ja auch direkt von Windows). Di musst du nicht "abfangen" Die TimerKomponente macht das von ganz allein. Die Frage ist nur, was machst du in der ganzen "Wartezeit" in der Methode Execute. Mit sleep warten funktioniert nicht. Du musst irgendeine "Wartefunktion" verwenden. Derer gibt es ein paar:
  1. GetMessage oder WaitMessage (wartet nur auf Windows-Messages)
  2. WaitForSingleObject, WaitForMultipleObjects (wartet auf Threads, Windows-Events, Mutex, Sempahore, Processe)
  3. MsgWaitForMultipleObjects (wartet auf beides 1 und 2 )
  4. ...andere blockierende Funktionen, bspw von den Sockets, die man nicht untereinander mischen kann

Jetzt musst du selber entscheiden, was du da hast, und was du am Ende für eine Funktion nehmen kannst. Achte aber darauf, dass du auch die Methode TThread.Terminate neu schreibst und den Abbruch entsprechend einleitest,

ThorvdA 30. Mai 2010 15:24

Re: Events in einem Thread
 
Klar, das mit dem Neuschreiben von Terminate hab ich verstanden (auch warum :) ).
Aber inwiefern kümmert sich der Timer selbst um die Events?

Delphi-Quellcode:
type TMeinthread = class(TThread)
                     private
                       Timer : TTimer;
                       procedure TimerEvent(Sender : TObject);
                     public
                       procedure Execute; override;
                       procedure Terminate;
                     end;

implementation

procedure TMeinthread.Execute;
var
  Msg : TMsg;
begin
  Timer:=TTimer.Create(nil);
  Timer.OnTimer:=TimerEvent;
  while GetMessage(Msg, 0, 0, 0) do
  begin
    // Was nun?
    // case Msg of
    //   WM_TIMER: TimerEvent(Timer); //
    // end;
    // ???
  end;
  Timer.Free;
end;

procedure TMeinthread.TimerEvent(Sender : TObject);
begin
  ShowMessage('Hallo'); // Wird nie ausgeführt ohne die case-Struktur
end;

procedure TMeinthread.Terminate;
begin
  PostThreadMessage(Self.ThreadID, WM_QUIT, 0, 0);
  inherited Terminate;
end;
Das Event kommt an, allerdings muss ich selbst darauf reagieren, oder?
Also z.B. mit der passenden case-Struktur?

Das heißt wenn ich eigene Objekte mit eigenen Events benutze, müsste ich beim Erstellen des Objekts vom Thread die ThreadID übergeben und das Ereigis wird dann druch PostThreadMessage ausgelöst?

sirius 30. Mai 2010 19:52

Re: Events in einem Thread
 
Du kannst natürlich selber mit bspw. case..of auf GetMessage reagieren. Oder du lässt es einfach Windows machen, in dem du DispatchMessage aufrufst. Die TimerKomponente hat sich extra dafür bei Windows "angemeldet".

btw.: In Terminate solltest du besser die beiden Befehle umdrehen. Ist zwar bei dir völlig unerheblich. Aber für zukünftige Projekte.
Denn Deine Vorfahrmethode macht nix weiter als die Variable FTerminated auf True zu setzen. Wenn du jetzt folgenden Konstrukt hast:
Delphi-Quellcode:
repeat
  while GetMEssage(msg,...) do
    Dispatchmessage(msg);
 //hier noch etwas anderes tun
until terminated;
...könnte es zu einem Laufzeitproblem kommen, wenn du erst WM_Quit setzt und dann FTerminated auf True.

samso 31. Mai 2010 06:43

Re: Events in einem Thread
 
Ich glaube, es ist keine gute Idee die TTimer-Komponente in in der Execute-Methode zu erzeugen, denn TTimer ist Teil der VCL und deshalb nicht Thread-safe. Details dazu unter:

AllocateHwnd is not Thread-Safe

ThorvdA 31. Mai 2010 23:29

Re: Events in einem Thread
 
Wunderbar ich habs verstanden :)
Danke!

@samso:
Dann funktioniert es aber leider nichtmehr (bzw der falsche Thread führt TimerEvent aus)... Es kommen dann keine Nachrichten bei meinem eigenen Thread an (ich vermute weil der Timer ja von "Hauptthread" erstellt wurde, sich mit dieser ThreadID bei Windows "angemeldet" hat und somit der die Nachrichten erhält).

Achja: Für mich ist das Problem gelöst, aber ich beteilige mich gern noch an Diskussionen zu ThreadSafe :)
Ich weiß ja nicht wie genau das hier genommen wird mit dem Markieren von Gelöstem.

dominikkv 1. Jun 2010 12:35

Re: Events in einem Thread
 
Zitat:

Zitat von ThorvdA
@samso:
Dann funktioniert es aber leider nichtmehr (bzw der falsche Thread führt TimerEvent aus)...

Andersherum funktioniert es aber auch nicht! Bzw vielleicht scheint es zu funktionieren, wunder dich aber nicht, wenn du in einem großen Projekt plötzlich an den verschiedensten Stellen Fehlermeldungen bekommst. Und dann viel Spaß beim Debuggen!

Lösung: TTimer im Hauptthread erstellen und im OnTimer den Workthread informieren (zB über Messages)


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:12 Uhr.
Seite 1 von 2  1 2      

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