![]() |
Thread Synchronize Fragen
Ich versuche seit ein paar Tagen meinen Thread zu optimieren, sodass ich ohne Synchronize arbeiten kann. Hierzu ein paar Fragen:
- muss ich das Setzen eines Tray-Icon-Hints synchronisieren? - wie kann ich Position und Hint einer ProgressBar ohne Synchronize setzen? Ich habe meinem Thread das Handle meiner ProgressBar übergeben und dann folgendes versucht
Delphi-Quellcode:
Leider tut sich dabei exakt nichts! PostMessage funktioniert auch nicht.
ProgressBarHandle:; THandle;
SendMessage(ProgressBarHandle, PBM_SETPOS, 55, 0); Aktuell verwende ich
Delphi-Quellcode:
statt Synchronize.
TThread.ForceQueue()
|
AW: Thread Synchronize Fragen
Synchronize blockiert deinen Thread bis der Befehl abgearbeitet wurde. Für das Setzen eines Hints oder eine Fortschrittsanzeige ist diese Synchronizität aber gar nicht notwendig. Hier kannst du auch einfach
Delphi-Quellcode:
einsetzen, was deinen Thread eben nicht blockiert, sonst aber dasselbe macht.
Queue
Delphi-Quellcode:
ist nur dann sinnvoll, wenn der Aufruf sowohl aus einem Neben- als auch aus dem Hauptthread erfolgen kann.
ForceQueue
|
AW: Thread Synchronize Fragen
Kann man also festhalten Queue ist besser als Synchronize?
Zitat:
Verstehe ich das richtig? Synchronize synchronisiert sofort und erst wenn das fertig ist geht es nach meinem Befehl, der in Synchronize() steht weiter und Queue packt den Aufruf in eine ART Stack, es geht aber sofort weiter? Nur kann Queue dann nicht Probleme machen wenn man folgendes Szenario hat?
Delphi-Quellcode:
Könnte es denn jetzt passieren, dass
var i: Integer;
i := 2; TThread.Queue(nil, procedure begin i := 5; end); if i = 5 then begin end;
Delphi-Quellcode:
ins Queue gesetzt wird aber erst so spät ausgeführt wird, dass
i := 5
Delphi-Quellcode:
nicht zutrifft, da i ja noch 2 ist?
if i := 5
Oder denke ich hier falsch? |
AW: Thread Synchronize Fragen
Richtig,
Delphi-Quellcode:
ist asynchron,
Queue()
Delphi-Quellcode:
ist synchron (höhö)
Synchronize()
PS: Doch, genau in dem Fall willst du ganz sicher NICHT einen asynchronen Aufruf verwenden. Denn das Setzen auf fünf passiert praktisch garantiert NACH deiner Abfrage. |
AW: Thread Synchronize Fragen
Könnte mein oben genanntes Problem denn eintreten?
i := 5 ist nur ein Beispiel. |
AW: Thread Synchronize Fragen
Du hast zwei Möglichkeiten: Synchron (
Delphi-Quellcode:
) und asynchron (
TThread.Synchronize(..)
Delphi-Quellcode:
)
TThread.Queue(..)
Wenn du die Auswirkungen/Resultate/Rückgaben des Codes den du im Kontext eines anderen Threads ausführen möchtest direkt brauchst, dann brauchst du
Delphi-Quellcode:
TThread.Synchronize(..)
Das "Problem" wird garantiert auftreten, hier noch einmal das gleiche Beispiel, nur etwas ausführlicher:
Delphi-Quellcode:
procedure TForm17.Button1Click(Sender: TObject);
begin TThread.CreateAnonymousThread( procedure() var capturedVariable: Integer; begin capturedVariable := 100; TThread.Queue( nil, procedure() begin capturedVariable := 42; end ); case capturedVariable of 100: Beep(); 42: begin Beep(); Beep(); end; else Beep(); Beep(); Beep(); end; end ).Start(); end; |
AW: Thread Synchronize Fragen
SendMessage und PostMessage synchronisieren sich selbstständig,
die Messages werden im Erstellungsthread der Komonenten verarbeitet, also innerhalb der MessageLoop. (bei der VCL im Hauptthread). PostMessage ist asynchron (ist wie Queue) SendMessage ist synchron (wie Synchronize) Achtung: TThread.Queue im Haupthtread aufgerufen ist synchron, also wie Synchronize (k.A. wer da auf diese schwachsinnige Idee gekommen ist) [edit] Seit wann gibt es ForceQueue? |
AW: Thread Synchronize Fragen
Seit 10.1 Berlin 8-)
|
AW: Thread Synchronize Fragen
Zitat:
Zitat:
![]() |
AW: Thread Synchronize Fragen
CriticalSection
MultiReaderSingleWriter Interlocked Interlocked: Setzen von Integer, Booleans (LongBool) usw., also allem mit "4 Byte", bzw. in Registergröße. ![]() ![]() |
AW: Thread Synchronize Fragen
Zitat:
|
AW: Thread Synchronize Fragen
Zitat:
Delphi-Quellcode:
unit Unit17;
interface uses System.SysUtils, System.Classes, Winapi.Windows, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.ComCtrls; type TMyThread = class(TThread) protected var progressbarHandle: THandle; protected procedure Execute(); override; public constructor Create(const progressbarHandle: THandle); end; TForm1 = class(TForm) ProgressBar1: TProgressBar; Button1: TButton; procedure Button1Click(Sender: TObject); end; var Form1: TForm1; implementation uses Winapi.CommCtrl; {$R *.dfm} { TMyThread } constructor TMyThread.Create(const progressbarHandle: THandle); begin inherited Create(True); self.progressbarHandle := progressbarHandle; end; procedure TMyThread.Execute(); var percentDone: Integer; begin percentDone := 0; while (not Terminated) do begin Inc(percentDone, 1); PostMessage(progressbarHandle, PBM_SETPOS, percentDone, 0); if (percentDone < 100) then TThread.Sleep(100) else Terminate(); end; end; procedure TForm1.Button1Click(Sender: TObject); var myThread: TMyThread; begin myThread := TMyThread.Create(ProgressBar1.Handle); myThread.FreeOnTerminate := True; myThread.Start(); end; end. Bonuspuntke für mehrmaliges Drücken des Buttons :wink: |
AW: Thread Synchronize Fragen
Zitat:
|
AW: Thread Synchronize Fragen
Funktioniert bei mir leider trotzdem nicht.
|
AW: Thread Synchronize Fragen
(Hier könnte ihre Werbung stehen)
|
AW: Thread Synchronize Fragen
Zitat:
So ist die grobe Richtung. Gruß K-H |
AW: Thread Synchronize Fragen
Zitat:
Pseudo!
Delphi-Quellcode:
* diese Arbeit kann etwas dauern. In dieser Prozedur1 wird auch mein Thread erst erzeugt.
- MainForm > Button1Click
-- UnitX.Prozedur1 wird aufgerufen* -- while-Schleife** -- ein paar Sachen werden noch in UnitX.Prozedur1 erledigt - wenn fertig, gehts zurück zu Button1Click (Aufrufer), ein paar Sachen werden noch erledigt und der Code ist beendet. **Nachdem der Thread erzeugt wurde warte ich mit
Delphi-Quellcode:
while ... solange der thread läuft ... do begin Application.ProcessMessages; Sleep(1000); end;
|
AW: Thread Synchronize Fragen
Wozu dann der Thread, wenn du eh Sleep im Mainthread aufrufst? Dann kannste auch alles gleich darin (im Button1Click) ausführen.
|
AW: Thread Synchronize Fragen
Zitat:
Gruß K-H |
AW: Thread Synchronize Fragen
Das ist sehr alter Code.
Ohne die Threads (es gibt mehrere Worker-Threads) würde das gar nicht so funktionieren wie ich es möchte und wie es aktuell auch ist. |
AW: Thread Synchronize Fragen
Zitat:
|
AW: Thread Synchronize Fragen
Ja. Wenn ich das so alles in meine MainForm packe funktioniert es. Deswegen ja meine Vermutung mit der While-Schleife.
|
AW: Thread Synchronize Fragen
Zitat:
Gruß K-H |
AW: Thread Synchronize Fragen
Ich habe gerade etwas getestet und etwas herausgefunden.
Jeglicher Code der nach der While-Schleife (die ja nach der Erzeugung der Threads kommt) kommt, wurde jetzt weggelassen. Button1Click wird ebenfalls per Exit nach Aufruf von UnitX.Prozedur1 sofort verlassen. Selbst dann funktioniert PostMessage nicht. Dahingegen funktioniert im Thread aber sogar ein unsynchronisierted/un-queu'tes
Delphi-Quellcode:
FrmMain.Caption := IntToStr(i);
Könnte es daran liegen, dass ich ein TApplicationEvents auf dem Form habe und ApplicationEvents1Message verwende? |
AW: Thread Synchronize Fragen
Zitat:
Das Postmessage braucht eine Gegenseite, die die Message annimmt, und dann wird immer noch eine Anzeige benötigt. Zitat:
Gruß K-H |
AW: Thread Synchronize Fragen
Zitat:
Ich verwende eh schon TApplicationMessage. Kann ich da die PBM_SETPOS-Message abfangen? |
AW: Thread Synchronize Fragen
Zitat:
|
AW: Thread Synchronize Fragen
Zitat:
HWND hWnd, // handle of destination window UINT Msg, // message to post WPARAM wParam, // first message parameter LPARAM lParam // second message parameter );" Was glaubst Du verbirgt sich hinter handle of destination window? und dort wird die Message verarbeitet, und sei es durch ignorieren.... Gruß K-H |
AW: Thread Synchronize Fragen
Ich weiß jetzt nicht genau wie das funktionieren soll, da ich einerseits in Button1Click am Ende etwas ausführe aber auch schon vorher nach der While-Schleife in UnitX.Prozedur1.
Einfach 2x das was du sagtest? Zitat:
![]() Von mehr habe ich auch keine Ahnung. Zitat:
Es funktioniert jetzt. Ich habe vorher laut Entwickler-Ecke das Handle der Progressbar übergeben. |
AW: Thread Synchronize Fragen
Ich habe jetzt soweit alle Synchronize und TTHread.Queue entfernt und durch PostMessage ersetzt.
Um das alles ordentlich handeln zu können habe ich ein paar const angelegt, die ich den PostMessage übergebe und dann in WndProc mit einem Case auswerte. Das Case hat 7 Blöcke. Ist das schon besser als für alles ein Synchronize zu verwenden? Die Bedienung der GUI fühlt sich, wenn Threads laufen und PostMessage's abschicken statt Synchronize ausführen, jetzt in jedem Fall wesentlich "flüssiger" an. Man merkt gar nicht mehr, dass im Hintergrund etwas arbeitet. Meine Konstanten sind aber noch fragwürdig.
Delphi-Quellcode:
Geht das nicht besser als mit
... = WM_USER + 1;
... = WM_USER + 2; ... = WM_USER + 3;
Delphi-Quellcode:
?
WM_USER + N;
|
AW: Thread Synchronize Fragen
Blub :lol: (siehe Seite 3)
|
AW: Thread Synchronize Fragen
Zitat:
Delphi-Quellcode:
bleiben willst, nein. Ich würde
PostMessage
Delphi-Quellcode:
verwenden. Das ist wesentlich besser lesbar und deutlich flexibler.
TThread.Queue
|
AW: Thread Synchronize Fragen
Zitat:
Es ist besser lesbar und dafür gibt es 100 Punkte mehr als für PostMessage. Aber PostMessage, muss man leider sagen, ist wesentlich performanter wenn man das mehrere Tausend mal in 20 Sekunden ausführt. |
AW: Thread Synchronize Fragen
Zitat:
Zitat:
Die auszuführende Prozedur wird per Queue in eine Liste geschrieben. Dann wird der Hauptthread aufgeweckt indem ihm per PostMessage (sieh mal an!) ein WM_NULL geschickt wird. In der Application.WndProc wird diese Message dann mit einem CheckSynchronize verarbeitet. Das CheckSynchronize arbeitet dann alle aktuell in der Liste stehenden Queue-Procs ab. Gegenüber einer reinen PostMessage-Lösung könnte sich hier eigentlich nur die Verwaltung der Liste auf die Performance auswirken. |
AW: Thread Synchronize Fragen
Zitat:
Der Quelltext ist dadurch sehr viel kürzer und übersichtlicher geworden und wurde von der Performance her tendentiell eher etwas schneller. Einen großen eindeutig messbaren Unterschied gab es jedenfalls nicht und damit gewinnt der bessere Code. |
AW: Thread Synchronize Fragen
Zitat:
Beispiel 2: gegeben ist ein Thread der alle 25ms die Position einer ProgressBar setzt. Gerade bei Beispiel 2 konnte ich große Unterschiede bzgl eines ruckelfreien Hauptformulars feststellen. |
AW: Thread Synchronize Fragen
Beispiel 3: der Thread ist schlau genug und muß das nicht alle 25ms tun
|
AW: Thread Synchronize Fragen
Mein Thread ist schlau genug :P er prüft vorher, ob sich die ProgressBar überhaupt bewegt hat :P ob es überhaupt etwas zu ändern gibt, indem ein paar Daten abgeglichen werden.
Zusätzlich habe noch so etwas drin
Delphi-Quellcode:
Ich komme jedenfalls gut klar mit den PostMessages. Ich finde es nun sauberer und perfomanter.
if (System.DateUtils.MilliSecondsBetween(Now, iCurrentTime) >= 500) then
begin // hier jetzt prüfen, ob ProgressBar überhaupt gesetzt werden muss iCurrentTime := Now; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:11 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