AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Verständnisfrage zur Verwendung von TMessageManager im Thread
Thema durchsuchen
Ansicht
Themen-Optionen

Verständnisfrage zur Verwendung von TMessageManager im Thread

Ein Thema von TiGü · begonnen am 29. Jul 2015 · letzter Beitrag vom 30. Jul 2015
Antwort Antwort
Seite 2 von 3     12 3      
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#11

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 13:25
Hm, stimmt...das die Werte noch an der Stelle im Speicher liegen, kann keiner garantieren.

Wie macht man es richtig?
Einen Zwischenspeicher nehmen, also einen weiteren Stack/Liste als Membervariable in der eigenen TThread-Ableitung, und dort dann reinkopieren?
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.126 Beiträge
 
Delphi 10.3 Rio
 
#12

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 13:27
s.o.
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#13

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 13:32
So geht der Q-Trick

Delphi-Quellcode:

  Procedure QWas(ADateTime : TDateTime);
  var
    LDateTime : TDateTime;
  begin
    LDateTime := ADateTeim;
    TThread.Queue(NIL,Procedure
     begin
       MachWasMit(LDateTime);
     end;
  end;

...
  QWas(DateTime);
...
Verflucht, wie einfach hinterher immer so eine Lösung aussieht! Danke Mav!
So ist das jetzt eine runde Sache.

Delphi-Quellcode:
procedure TMessageThread.SendDateTime(const ADateTime : TDateTime);
var
  LDateTime : TDateTime;
begin
  LDateTime := ADateTime;
  TThread.Queue(nil,
    procedure
    begin
      DoSendMessage(LDateTime);
    end);
end;

procedure TMessageThread.DoInternalExecute;
begin
  while not Terminated do
  begin
    try
      FLock.Enter;
      try
        if FStack.Count >= 25 then
        begin
          if not Terminated then
          begin
            while FStack.Count <> 0 do
            begin
              SendDateTime(FStack.Pop);
            end;
          end;
        end;
      finally
        FLock.Leave;
      end;
    finally
      Sleep(100);
    end;
  end;
end;

procedure TMessageThread.DoSendMessage(const ADateTime : TDateTime);
var
  LMessage : TDateTimeMessage;
begin
  LMessage := TDateTimeMessage.Create(ADateTime);
  TMessageManager.DefaultManager.SendMessage(Self, LMessage, True);
end;
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.126 Beiträge
 
Delphi 10.3 Rio
 
#14

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 13:41
Abgesehen davon, dass ich keinen Thread nehmen würde...

Weil die Message ruft Dich ja auf... Es gibt also keinen Grund zu "Pollen"
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#15

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 13:48
Ja, das Beispiel ist natürlich sinnbefreit, weil hier Daten aus dem Main-Thread in den anderen Thread und wieder zurückgeschaufelt werden.
Aber mir gings ja um die grundsätzliche Heransgehensweise.
Über den TMessageManger können ja ganz andere Daten an einen Thread übergeben werden, der zum Beispiel nach N-Werten anfängt darauf eine lange Operation auszuführen und das Ergebnis wieder zurück an den Main-Thread zu übergeben.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#16

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 14:02
Dann spendier dem Thread doch wenigstens einen Event damit der nicht immer wie doof herumrödelt auch wenn es nichts zu tun gibt.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.126 Beiträge
 
Delphi 10.3 Rio
 
#17

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 14:02
Ja, das Beispiel ist natürlich sinnbefreit, weil hier Daten aus dem Main-Thread in den anderen Thread und wieder zurückgeschaufelt werden.
Aber mir gings ja um die grundsätzliche Heransgehensweise.
Über den TMessageManger können ja ganz andere Daten an einen Thread übergeben werden, der zum Beispiel nach N-Werten anfängt darauf eine lange Operation auszuführen und das Ergebnis wieder zurück an den Main-Thread zu übergeben.
Das würde ich auf jeden Fall anders machen...

Delphi-Quellcode:
procedure TMyThread.Execute;
begin
  while not(Terminated) do
    begin
      try
        E_Event.WaitFor(INFINITE);
    
        if Terminated then
          exit;

        MyExecute; // Hier findet die Eigentliche Verarbeitung statt.
      except
      end;
    end;
end;

...
  FSaveID := TMessageManager.DefaultManager.SubscribeToMessage(TWhatever,
                 Procedure(Const Sender:TObject;Const M:TFMXMessage)
                   begin
                     FVerarbeite := TWhatEver(M).Value.Daten;
                     E_Event.SetEvent;
                   end);
...
Tests ob der Thread noch läuft usw.. habe ich mir jetzt gespart...
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#18

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 14:47
Soweit in Ordnung?
Ich löse das Event und damit die Verarbeitung aus, wenn der Thread mehr als 25 Items erhalten hat.
Da ich die Instanz von TEvent im Formular erzeuge und dem TThread per Konstruktor übergebe, habe ich mir die Möglichkeit offen gelassen, ggf. auch aus dem Formular heraus das Event zu setzen.
Kann man das so machen?

Delphi-Quellcode:
unit Messagner.View;

interface

uses
  System.SysUtils, System.Classes, System.Types,
  System.Messaging, System.SyncObjs, System.Generics.Collections,
  Vcl.Controls, Vcl.Forms, Vcl.StdCtrls;

type
  TIdleMessage = class(System.Messaging.TMessage)
  end;

  TDateTimeMessage = class(System.Messaging.TMessage<TDateTime>)
  end;

  TMessageThread = class(TThread)
  private
    FLock : TCriticalSection;
    FStack : TStack<TDateTime>;
    FEvent : TEvent;

    procedure GetIdleMessage(const Sender : TObject; const M : TMessage);
    procedure DoSendMessage(const ADateTime : TDateTime);
    procedure DoInternalExecute;
    procedure SendDateTime(const ADateTime : TDateTime);
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    procedure BeforeDestruction; override;
    constructor Create(const AEvent : TEvent);
    destructor Destroy; override;
  end;

  TForm1 = class(TForm)
    mmoLog : TMemo;
    procedure FormCreate(Sender : TObject);
    procedure FormDestroy(Sender : TObject);
  private
    FMessageThread : TMessageThread;
    FIdleMessage : TIdleMessage;
    FEvent: TEvent;
    procedure ThreadTerminated(Sender : TObject);
    procedure OnNewDateTimeMessage(const Sender : TObject; const M : TMessage);
    procedure LogToMemo(const Text : string);
  public
    procedure DoIdle(Sender : TObject; var Done : Boolean);
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}


procedure TForm1.LogToMemo(const Text : string);
begin
  mmoLog.Lines.Add(Text);
end;

procedure TForm1.OnNewDateTimeMessage(const Sender : TObject; const M : TMessage);
var
  LMessage : TDateTimeMessage;
begin
  LMessage := M as TDateTimeMessage;
  LogToMemo('- - - > ' + FormatDateTime('hh:mm:ss:zzz', LMessage.Value));
end;

procedure TForm1.DoIdle(Sender : TObject; var Done : Boolean);
begin
  TMessageManager.DefaultManager.SendMessage(Self, FIdleMessage, False);
end;

procedure TForm1.FormCreate(Sender : TObject);
begin
  FIdleMessage := TIdleMessage.Create;
  Vcl.Forms.Application.OnIdle := DoIdle;
  FEvent := TEvent.Create();
  FMessageThread := TMessageThread.Create(FEvent);
  FMessageThread.OnTerminate := ThreadTerminated;
  TMessageManager.DefaultManager.SubscribeToMessage(TIdleMessage, FMessageThread.GetIdleMessage);
  TMessageManager.DefaultManager.SubscribeToMessage(TDateTimeMessage, OnNewDateTimeMessage);
end;

procedure TForm1.ThreadTerminated(Sender : TObject);
var
  LException : Exception;
begin
  TMessageManager.DefaultManager.Unsubscribe(TIdleMessage, FMessageThread.GetIdleMessage);
  if Sender is TThread then
  begin
    if TThread(Sender).FatalException is Exception then
    begin
      LException := Exception(TThread(Sender).FatalException);
      LogToMemo(LException.ToString + ' ' + LException.Message);
    end;
  end;
end;

procedure TForm1.FormDestroy(Sender : TObject);
begin
  FMessageThread.Free;
  FIdleMessage.Free;
  FEvent.Free;
end;

{ TMessageThread }

procedure TMessageThread.BeforeDestruction;
begin
  FStack.Free;
  inherited;
end;

constructor TMessageThread.Create(const AEvent : TEvent);
begin
  inherited Create;
  FEvent := AEvent;
  NameThreadForDebugging('Message-Thread');
  FLock := TCriticalSection.Create;
  FStack := TStack<TDateTime>.Create;
end;

procedure TMessageThread.SendDateTime(const ADateTime : TDateTime);
var
  LDateTime : TDateTime;
begin
  LDateTime := ADateTime;
  TThread.Queue(nil,
    procedure
    begin
      DoSendMessage(LDateTime);
    end);
end;

procedure TMessageThread.TerminatedSet;
begin
  inherited;
  FEvent.SetEvent;
end;

destructor TMessageThread.Destroy;
begin
  inherited;
  FLock.Free;
end;

procedure TMessageThread.DoInternalExecute;
begin
  FLock.Enter;
  try
    if FStack.Count >= 25 then
    begin
      if not Terminated then
      begin
        while FStack.Count <> 0 do
        begin
          SendDateTime(FStack.Pop);
        end;
      end;
    end;
  finally
    FLock.Leave;
  end;
end;

procedure TMessageThread.DoSendMessage(const ADateTime : TDateTime);
var
  LMessage : TDateTimeMessage;
begin
  LMessage := TDateTimeMessage.Create(ADateTime);
  TMessageManager.DefaultManager.SendMessage(Self, LMessage, True);
end;

procedure TMessageThread.Execute;
var
  WaitResult : TWaitResult;
begin
  inherited;
  while not Terminated do
  begin
    WaitResult := FEvent.WaitFor();
    if WaitResult = TWaitResult.wrSignaled then
    begin
      if not Terminated then
      begin
        DoInternalExecute;
      end;
    end;
  end;
end;

procedure TMessageThread.GetIdleMessage(const Sender : TObject; const M : TMessage);
var
  NowDateTime, LastDateTime : TDateTime;
begin
  FLock.Enter;
  try
    NowDateTime := System.SysUtils.Now;

    if FStack.Count <> 0 then
    begin
      LastDateTime := FStack.Peek;
      if LastDateTime <> NowDateTime then
      begin
        FStack.Push(NowDateTime);

        if FStack.Count >= 25 then
        begin
          FEvent.SetEvent;
        end;
      end;
    end
    else
    begin
      FStack.Push(NowDateTime);
    end;
  finally
    FLock.Leave;
  end;
end;

end.
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.126 Beiträge
 
Delphi 10.3 Rio
 
#19

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 29. Jul 2015, 16:33
Soweit in Ordnung?
Ich löse das Event und damit die Verarbeitung aus, wenn der Thread mehr als 25 Items erhalten hat.
Da ich die Instanz von TEvent im Formular erzeuge und dem TThread per Konstruktor übergebe, habe ich mir die Möglichkeit offen gelassen, ggf. auch aus dem Formular heraus das Event zu setzen.
Kann man das so machen?
Abgesehen davon, das die Events in umgekehrter Reihenfolge raus kommen, Du immer noch nicht die ID's speicherst die Du für den Unsubscripe brachst... Schon OK...
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#20

AW: Verständnisfrage zur Verwendung von TMessageManager im Thread

  Alt 30. Jul 2015, 08:16
Kann man das so machen?
Abgesehen davon, das die Events in umgekehrter Reihenfolge raus kommen, Du immer noch nicht die ID's speicherst die Du für den Unsubscripe brachst... Schon OK...
Das mit der Reihenfolge ist egal, aber die IDs von SubscribeToMessage zu speichern ist doch nur optional?!
Unsubscribe hat doch noch zwei weitere Überladungen (http://docwiki.embarcadero.com/Libra...er.Unsubscribe).
Bei einer relativ geringen Menge an Subscribers pro MessageClass ist die Iteration über die Liste doch stark vernachlässigbar oder täusche ich mich?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:54 Uhr.
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