Einzelnen Beitrag anzeigen

Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: TThread: Synchronize() priorisieren?

  Alt 29. Mär 2016, 16:06
Ich rufe damit eine Metode des Grids (GUI), die für die Visualisierung der Daten zuständig ist. Oder was ist mit einem Event gemeint?
Mit dem Event war gemeint, den Thread nicht von deiner Oberfläche abhängig zu machen. Den Thread sollte es nichts angehen, was wie auf welche Labels kommt, sondern man sollte ihm von außen übergeben, was getan werden soll wenn neue Daten gesammelt wurden. Dann kannst man auch die Oberfläche komplett überarbeiten ohne die Logik im Hintergrund wieder anfassen zu müssen. Oder die Threads in einer anderen Anwendung wiederverwenden. Oder man kommt nicht aus dem Tritt wenn die Temperatur bei manchen Kunden nun bitte in Fahrenheit und nicht Celsius angezeigt werden soll.


Als Beispiel mit TNotifyEvent , im Endeffekt das gleiche wie das OnClick bei einem TButton :

Formular:
(Braucht ein Label "airPressureLabel" und ein "temperatureLabel")
Delphi-Quellcode:
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.
Zweite Unit "Threads":

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.
  Mit Zitat antworten Zitat