![]() |
TThread: Synchronize() priorisieren?
Hallo!
Ich habe mehrere Threads, die zeitkritische Daten aus unterschiedlichen Quellen geliefert bekommen. Die Threads haben alle eins gemeinsam: irgendwan greifen die alle an ein bestimmtes GUI-Objekt zu, synchroniziert natürlich. Besteht die Möglichkeit, einen Thread so zu priorisieren, dass er immer Vorrang bei synchronisiertem Zugriff auf die GUI hat? Dabei möchten ich keinesfalls die gesammte Thread-Prioritöt verändern, sondern nur das es bei Synchronize höhere Priorität hat. Geht das irgendwie? Danke! |
AW: TThread: Synchronize() priorisieren?
Nein, wer zuerst kommt, malt zuerst.
Die Liste der Synchronisationen wird der Reihe nach abgearbeitet. Wenn nicht gewünscht, dann wirst du die Synchronisierung wohl selber implementieren müssen. z.B. die "Callbacks" in eine TThreadList eintragen, dann eine Message (Send oder Post) an den Hauptthread schicken und da diese Liste priorisiert abarbeiten. |
AW: TThread: Synchronize() priorisieren?
Was er sagt: Synchronize ist ein blockierender Aufruf. Er stellt dem Hauptthread einen Methodenzeiger in einer "Hier, arbeite das ab"-Warteschlange hinten an. Die Reihenfolge könnte man vielleicht mit viel Gefummel verändern, aber ich glaube was du vorhast ist nicht der beste Ansatz.
Der Thread sollte gar nichts mit der Oberfläche zu tun haben sondern nur die jeweils aktuellen Daten bereitstellen. Wenn es neue Daten gibt, kann er ja ein Event auslösen und die Oberfläche zeigt die jeweils aktuellen Daten an wie sie grade Lust hat. |
AW: TThread: Synchronize() priorisieren?
Man sollte auch prüfen, ob das
Delphi-Quellcode:
hier nicht durch ein
Synchronize
Delphi-Quellcode:
ersetzt werden kann. Solange der Thread nicht auf das Ergebnis bzw. den Abschluss der Synchronize-Operation angewiesen ist, wäre Queue (non-blocking) hier vielleicht die bessere Wahl.
Queue
|
AW: TThread: Synchronize() priorisieren?
Danke für die schnelle Reaktionen!
Zitat:
Zitat:
|
AW: TThread: Synchronize() priorisieren?
Zitat:
Synchronize = Arbeite diese Methode bei nächter Gelegenheit im Hauptthread ab und warte solange bis sie fertig ist.Es kann allerdings passieren, daß bei Queue die Methode gar nicht abgearbeitet wird, da bei Freigabe der TThread-Instanz alle noch vorhandenen Queue-Events gelöscht werden. Dem kann man aber vorbeugen, in dem man anstatt der einfachen Queue-Methode die gleichnamige Klassenmethode mit dem zusätzlichen TThread-Parameter an erster Stelle verwendet und diesen als nil übergibt. Dann kann das zwar theoretisch immer noch passieren, aber nur wenn das ganze Programm vor Abarbeiten des Queue-Events beendet wird. Das wäre übrigens bei Synchronize auch der Fall. |
AW: TThread: Synchronize() priorisieren?
Zitat:
Als Beispiel mit
Delphi-Quellcode:
, im Endeffekt das gleiche wie das
TNotifyEvent
Delphi-Quellcode:
bei einem
OnClick
Delphi-Quellcode:
:
TButton
Formular: (Braucht ein Label "airPressureLabel" und ein "temperatureLabel")
Delphi-Quellcode:
Zweite Unit "Threads":
unit Unit3;
interface uses System.SysUtils, System.SyncObjs, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Threads ; type TForm3 = class(TForm) temperatureLabel: TLabel; airPressureLabel: TLabel; procedure FormCreate(Sender: TObject); private var airPressureThread: TPressureThread; temperatureThread: TTemperatureThread; private procedure handleNewData(Sender: TObject); end; var Form3: TForm3; implementation {$R *.dfm} procedure TForm3.FormCreate(Sender: TObject); begin airPressureThread := TPressureThread.Create(True); temperatureThread := TTemperatureThread.Create(True); airPressureThread.OnNewData := handleNewData; temperatureThread.OnNewData := handleNewData; airPressureThread.Start(); temperatureThread.Start(); end; procedure TForm3.handleNewData(Sender: TObject); var value: Single; begin if (Sender = airPressureThread) then begin value := airPressureThread.getAirPressure(); airPressureLabel.Caption := String.Format('Pressure: %f Pa', [value]); end; if (Sender = temperatureThread) then begin value := temperatureThread.getTemperature(); temperatureLabel.Caption := String.Format('Temperature: %f °C', [value]); end; end; end.
Delphi-Quellcode:
unit Threads;
interface uses System.Classes, System.SyncObjs; type /// <summary> /// Abstrakte Oberklasse für Threads die Daten /// bereitstellen und mit <c>OnNewData</c> signalisieren /// dass neue Daten bereitliegen /// </summary> TDataThread = class(TThread) protected var mutex: TSynchroObject; protected procedure triggerNewDataEvent(); public var /// <remarks> /// Wird immer <b>im Hauptthread</b> ausgeführt /// </remarks> OnNewData: TNotifyEvent; public constructor Create(const CreateSuspended: Boolean); destructor Destroy(); override; end; TTemperatureThread = class(TDataThread) protected const noTemperature = -273.15; protected var FTemperature: Single; protected function retrieveTemperature(): Single; procedure Execute(); override; public constructor Create(const CreateSuspended: Boolean); /// <returns> /// Temperatur in °C /// </returns> /// <remarks> /// Wenn noch keine Temperatur aufgezeichnet wurde wird /// <c>-273.15</c> zurückgegeben /// </remarks> function getTemperature(): Single; end; TPressureThread = class(TDataThread) protected procedure Execute(); override; /// <returns> /// Druck in Pa /// </returns> public function getAirPressure(): Single; end; implementation { TDataThread } constructor TDataThread.Create(const CreateSuspended: Boolean); begin inherited Create(CreateSuspended); mutex := TCriticalSection.Create(); end; destructor TDataThread.Destroy(); begin mutex.Free(); inherited; end; procedure TDataThread.triggerNewDataEvent(); begin if not Assigned(OnNewData) then Exit; TThread.Queue( nil, procedure() begin OnNewData(self); end ); end; { TTemperatureThread } constructor TTemperatureThread.Create(const CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FTemperature := noTemperature; end; procedure TTemperatureThread.Execute(); var currentTemperature: Single; begin while (not Terminated) do begin currentTemperature := retrieveTemperature(); if (currentTemperature = noTemperature) then Continue; mutex.Acquire(); try FTemperature := currentTemperature; finally mutex.Release(); end; triggerNewDataEvent(); end; end; function TTemperatureThread.getTemperature(): Single; begin mutex.Acquire(); try Result := FTemperature; finally mutex.Release(); end; end; function TTemperatureThread.retrieveTemperature(): Single; begin Sleep( 1000 + Random(1000) ); Result := 42.0 + Random() * 10.0; end; { TPressureThread } procedure TPressureThread.Execute(); begin while (not Terminated) do begin // Platzhalter end; end; function TPressureThread.getAirPressure(): Single; begin // Platzhalter end; end. |
AW: TThread: Synchronize() priorisieren?
Zitat:
Zitat:
Beispiel für Queue aus dem Thread oder wie Günther es geschrieben hat ein Event dann die Daten von der anderen Seite aus holt... Beispiel: Ein Thread erzeugt permanent Daten und zwar nicht nur ein Integer sonst was kompliziertes... Bei einem Syncronize musst du zwar warten auf den UI-Thread aber kannst sicher danach die Daten verwerfen... Bei ein Queue Aufruf, musst Du sicher stellen, dass zum Zeitpunkt wo der UI-Thread die Daten darstellen will, die Daten auch noch vorhanden sind. Noch schwieriger ist es, wenn Du die Kontrolle - wie Günther - an ein anderes Programmteil übergeben hast... Denn falls der UI-Thread die Daten lesen will, muss sichergestellt werden, dass der Thread die Daten nicht gerade neu- oder überschreibt. Musst Du alle Zwischenschritte immer darstellen? Ich habe hier z.B. eine Routine programmiert, die immer wenn der Thread neue Daten erzeugt und der UI-Thread die Daten noch nicht verarbeitet hat, der letzte Datensatz verworfen und sofort gegen den neuen Ausgetauscht wird. Für Dein Problem, würde ich einfach 2 oder wie viele auch immer Du brauchst eigenen Threadsichere Queues erzeugen und diese über einen Workerthread der gemäß Priorität die einzelen Queues abarbeitet und dann problemlos Syncronisieren kann. Mavarik |
AW: TThread: Synchronize() priorisieren?
Zitat:
|
AW: TThread: Synchronize() priorisieren?
Zitat:
Aber ich verstehe deinen Einwand/Ansatz! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:48 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