Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Probleme mit PostMessage aus einem Thread (https://www.delphipraxis.net/128810-probleme-mit-postmessage-aus-einem-thread.html)

deadcantdance 6. Feb 2009 15:28


Probleme mit PostMessage aus einem Thread
 
Hi,

sporadisch habe ich das Problem, dass mein Zeichnen der Controls auf meinem Formular Exceptions auftreten. Nach einiger Suche bin ich auf die vermutlichen Ursache gestoßen:

Ich habe ein Control, abgeleitet vom VirtualStringTree. Dieses Control besitzt eine Methode, die aus einem anderen Thread aufgerufen wird, um dem Control mitzuteilen, dass es sich aktualisieren soll. Um nicht direkt aus dem anderen Thread zu zeichnen, gehe ich wie folgt vor:

Delphi-Quellcode:
procedure MyControl.DoCallback;
begin
  PostMessage(Self.Handle, WM_MYCONTROLRELOAD, 0, 0);
end;
Außerdem gibt es noch eine Methode, die auf diese Nachricht reagiert:
Delphi-Quellcode:
procedure DoControlReload( var Message: TMessage); message WM_MYCONTROLRELOAD;

procedure MyControl.DoControlReload( var Message: TMessage);
begin
  ReloadfromDB;
  Invalidate;
end;
Das Problem ist nun, dass die Zeichenroutine des Controls aus dem Thread aufgerufen wird, der auch die Callback aufgerufen hat. Bisher war ich davon ausgegangen, dass wenn ich eine Nachricht mit PostMessage an mein Control schicke, diese auch im Hauptthread abgearbeitet wird. Das ist anscheinend nicht der Fall?!

Zusätzlich möchte ich noch erwähnen, dass der Thread im Execute eine while-Schleife beinhaltet, in der auch Application.ProcessMessages aufgerufen wird.

Meine Frage an Euch: Wie kann ich nun verhindern, dass die Zeichenroutine des Controls aus dem anderen Thread aufgerufen wird?

Viele Grüße,
deadcantdance

sirius 6. Feb 2009 15:33

Re: Probleme mit PostMessage aus einem Thread
 
Nimm das Application.ProcessMessages aus dem Thread raus :stupid:

deadcantdance 6. Feb 2009 15:44

Re: Probleme mit PostMessage aus einem Thread
 
Das kann ich nicht, der Thread läuft mit höherer Priorität, da es sich um den Kommunikationsthread handelt. Nehme ich die Anweisung raus, friert mir die GUI ein.

sirius 6. Feb 2009 16:06

Re: Probleme mit PostMessage aus einem Thread
 
Bau ein sleep(0) ein!

deadcantdance 6. Feb 2009 16:11

Re: Probleme mit PostMessage aus einem Thread
 
Hilft leider auch nicht, sobald ich in der GUI auf einen Button klicke, friert diese ein!

sirius 6. Feb 2009 16:13

Re: Probleme mit PostMessage aus einem Thread
 
Und "SwitchToThread;"?

Edit: Du solltest wahrscheinlich eher die Priorität etwas zurückschrauben.

deadcantdance 6. Feb 2009 16:23

Re: Probleme mit PostMessage aus einem Thread
 
Ich muss mich korrigieren, die Priority steht auf Normal.

SwitchToThread hilft leider auch nicht, CPU-Auslastung geht auf 100%

sirius 6. Feb 2009 16:37

Re: Probleme mit PostMessage aus einem Thread
 
Kein Ahnung, was du da machst.

Self.Handle ist auch noch ein Problem (aber ich vermute nicht das primäre). Besser ist du übergibst das Handle an das Threadobjekt und machst dort Postmessage.

Dann vielleicht mal sleep(x) (mit x>0). Damit hier mal etwas pausiert.

shmia 6. Feb 2009 16:39

Re: Probleme mit PostMessage aus einem Thread
 
Application.ProcessMessages darf nicht im Kontext des Threads laufen; da beisst keine Maus einen Faden ab!
Dein Thread sollte auch nicht unbedingt mit höherer Prio laufen.
Wenn dein Thread auf die Benutzeroberfläche zugreifen muss, dann immer mit der Methode Synchronize:
Delphi-Quellcode:
procedure TMyThread.Execute;
begin

  for i := ... to ... do
  begin
    FStatus := 'Lese '+ IntToStr(i);
    Synchronize(UpdateLabel);

    DatenLesen;

    FStatus := 'Verarbeite '+ IntToStr(i);
    Synchronize(UpdateLabel);
   
    Datenverarbeiten;
   
    Synchronize(UpdateGui);

    if Terminated then Exit; // wichtig, um den Thread sauber abbrechen zu können
  end;
end;

procedure TMyThread.UpdateLabel;
begin
  form1.StatusLabel.Caption := FStatus;
  form1.StatusLabel.Refresh;
end;

procedure TMyThread.UpdateGui;
begin
  form1.vsg1.items.Add(....);
  form1.vsg1.refresh;
end;
Der Trick ist nun, dass Synchronize eine Windows Botschaft in die Messagequeue setzt
und die Methode UpdateGui im Kontext der Hauptthreads ausgeführt wird.

Über Synchronize kannst du nur eine Methode ohne Parameter aufrufen.
Diese Einschränkung lässt sich umgehen, indem die Parameter als Variablen im Thread-Objekt gespeichert werden.

Übrigens:
Wenn dein Thread niemals wartet (WaitforMultipleObjects), dann ist es ganz normal, dass die CPU-Auslastung auf 100% geht!

messie 6. Feb 2009 17:39

Re: Probleme mit PostMessage aus einem Thread
 
Zitat:

Zitat von shmia
Application.ProcessMessages darf nicht im Kontext des Threads laufen; da beisst keine Maus einen Faden ab!

Auch wenn es leicht offtopic ist: warum ist das so und was passiert, wenn ich aus einem Thread eine Routine (ohne synchronize) aufrufe, in der das steht? Ich glaub' das habe ich schonmal irgendwo gemacht, ohne das es Probleme gab.
Ich dachte immer, Application.Processmessages erzwingt die Abarbeitung der Windows-Eventqueue. Das kann doch auch aus einem Thread sinnvoll sein, z.B. wenn es Zugriffe auf Datenbanken, Hardware-dlls etc. gibt.

Grüße, Messie

sirius 6. Feb 2009 17:47

Re: Probleme mit PostMessage aus einem Thread
 
Zitat:

Zitat von messie
Ich dachte immer, Application.Processmessages erzwingt die Abarbeitung der Windows-Eventqueue.

  1. Jeder Thread hat seine eigene MessageQueue
  2. Greifst du auf nicht threadeigene Variablen/Objekte zu
  3. ist es ja gerade der Sinn eines Threads. Die Messageabarbeitung im Hauptthread läuft ja nebenbei

deadcantdance 6. Feb 2009 20:27

Re: Probleme mit PostMessage aus einem Thread
 
Das Problem bei der Benutzung von Synchronize ist aber, dass der Thread erst dann weiterläuft, nachdem die Methode abgearbeitet wurde. Daher habe ich es ja bisher mit PostMessage probiert, damit der Thread sofort weiterlaufen kann.

Es handelt sich bei dem Thread um einen Kommunikations-Thread, der ständig Daten empfangen und senden soll, daher soll keine Zeit für das Updaten der GUI vom Thread verloren gehen.

sirius 6. Feb 2009 20:58

Re: Probleme mit PostMessage aus einem Thread
 
Also die GUI muss upgedatet werden, wenn den den Thread switched. Das verstehe ich nicht. Oder bist du auf einem Pentium 1 Prozessor?

deadcantdance 7. Feb 2009 13:11

Re: Probleme mit PostMessage aus einem Thread
 
Die GUI muss aus dem Hauptthread upgedatet werden. Daher habe ich bisher eine WM_User-Botschaft verschickt, da ich dachte, diese würde im Hauptthread abgearbeitet. Daher auch Applikation.ProcessMessages im Thread.

Nur wird die GUI halt aus dem anderen Thread geupdatet. Das ist mein Problem.

himitsu 7. Feb 2009 13:52

Re: Probleme mit PostMessage aus einem Thread
 
Application.ProcessMessages verarbeiter die Nachrichten und zwar in dem Thread, wo es aufgerufen wird.
wenn du also Application.ProcessMessages in einem Thread aufrufst, dann werden die Nachrichten auch in diesem Thread abgearbeitet und mit etwas Glück zankt sich dann die Nachrichtenverarbeitung des Programms mit der im Thread auch noch.

also Application.xyz hat nichts in einem Thread zu suchen.

Apollonius 7. Feb 2009 13:56

Re: Probleme mit PostMessage aus einem Thread
 
Windows lässt gar nicht zu, dass ein Thread für einen anderen Fensternachrichten abarbeitet. Jeder Thread erhält nur die Nachrichten für seine eigenen Fenster.

himitsu 7. Feb 2009 14:03

Re: Probleme mit PostMessage aus einem Thread
 
ok, dennoch nutzt er dann die Nachrichtenverarbeitung des Hauptthreads, auch wenn er damit die Nachrichten eines anderen Thread abarbeitet

deadcantdance 7. Feb 2009 17:14

Re: Probleme mit PostMessage aus einem Thread
 
Wie kann ich dann bitte ohne ein Einsatz von Synchronize den Hauptthread dazu bewegen, die GUI zu aktualisieren?


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