Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Object mit SendMessage an MainThread senden (https://www.delphipraxis.net/180871-object-mit-sendmessage-mainthread-senden.html)

Captnemo 27. Jun 2014 10:50

AW: Object mit SendMessage an MainThread senden
 
So hab ich es jetzt letztlich im Moment auch gelöst. Im MainTread eine Tobjectlist, vom Thread innerhalb ein TCriticalSection Daten hinzu, und per postmessage benachrichtigen.

Aber ich will mir auch nochmal die TThread.Queue anschauen, denn das find auch ganz interessant.

himitsu 27. Jun 2014 14:44

AW: Object mit SendMessage an MainThread senden
 
Nein, SendMessage/PostMessage ist in Threads kein Problem.

Beides trägt die Message in den MessageQueue des Threads ein, in welchem die Komponente erstellt wurde, an die die Message geht.
Verarbeitet wird die Message dann immer von der Messagebehandlung im zugehörigen Thread (meist der Hauptthread).


TThread.Queue ist wie Synchronize, außer daß die Prozedur nicht sofort verarbeitet wird. (von dem "Bug" abgesehn, wenn man was vom MainThread aus daran übergibt)

stoxx 27. Jun 2014 15:32

AW: Object mit SendMessage an MainThread senden
 
Zitat:

Zitat von Medium (Beitrag 1263623)
Eine Liste mit durch Critical Sections gesichertem Zugriff ist imho fast die einzige vernünftige Art Daten unter verschiedenen Threads auszutauschen. Dem Formular dann nur noch per PostMessage() parameterlos mitteilen, dass es da neues drin gibt, und dieses arbeitet immer schon Index 0 ab und löscht aus der Liste bis sie leer ist. FiFo-Style.

kann man zustimmen


Zitat:

Zitat von Medium (Beitrag 1263623)
Davon ab pausiert der Thread bis alle Handler von den Empfängern fertig sind, und das ist ja nun auch nicht ganz der Sinn von Parallelisierung.

besser Postmessage, oder SendMessageTimeOut verwenden, da bei SendMessage bis zur Bestätigung der Verarbeitung gewartet wird, da hätte man dann auch gleich synchronize verwenden können, wo der Thread ebenso bis zum Ende der Verarbeitung angehalten wird.


Zitat:

Zitat von Medium (Beitrag 1263623)
Am Rande: SendMessage() ist in Threads, wenn ich mich nicht grad irre, eigentlich sogar ein ziemliches NoGo, da alles was die Empfänger dann tun auf ein Mal im Thread-Kontext statt findet. Und das kann je nach dem auch schon mal so richtig böse knallen, da es OS Ressourcen gibt, die nur im erstellenden Kontext verwendet werden dürfen.

nein, das stimmt nicht, das ist kein Problem.
PostMessage, SendMessage usw geht in de Queue vom jeweiligem Thread.
Überprüfen kannst Du, von welchem Thread die Funktion aufgerufen wird mit: GetCurrentThreadID

Wenn ein eigener Thread wirklich seine Nachrichten auch behandeln will, sofern er überhaupt welche bekommt, dann mit PeekMessage, TranslateMessage in der Execute Schleife von TThread.

Medium 27. Jun 2014 16:23

AW: Object mit SendMessage an MainThread senden
 
Danke für die Aufklärung! War bisher zu faul das genauer zu testen. Das Problem was ich mal hatte wodurch ich dazu kam, war gelöst als ich noch eine ganze Menge mehr umgebaut habe. Das war dann also schon mal nicht der Suppenspucker.

Sir Rufo 27. Jun 2014 17:42

AW: Object mit SendMessage an MainThread senden
 
Um noch einmal auf das Über- und Freigeben von Instanzen durch, von, über in Verbindung von Thread und Mainthread zu sprechen zu kommen ...

Was soll denn hier erreicht werden?

Nehmen wir einmal das Beispiel mit
Delphi-Quellcode:
TLogMessage
.

Wir haben da also einen Thread, der irgendwas bearbeitet und zwischendurch immer wieder etwas melden soll. Dieser Thread soll aber durch das Senden dieser LogMessage nicht mehr als nötig ausgebremst werden (seine Hauptaufgabe besteht eben nicht im Versenden dieser LogMessage). Ok.

Warum versendet dieser Thread diese LogMessage denn dann überhaupt?

Geben wir diesem Thread doch einen Kumpel an die Hand, der dieses Versenden für ihn übernimmt.
Und dieser Kumpel darf ja auch gerne wiederum ein Thread sein (macht ja nichts).
Delphi-Quellcode:
type
  TBaseMessage = class abstract
  end;

  TNotifyMessageEvent = reference to procedure( Sender : TObject; AMsg : TBaseMessage );

  TMessageService = class( TThread )
  private
    FCS : TCriticalSection;
    FEvent : TEvent;
    FMessages : TQueue<TBaseMessage>; <--- da kommen die rein
    FOnMessage : TNotifyMessageEvent;
    function GetOnMessage : TNotifyMessageEvent;
    procedure SetOnMessage( const Value : TNotifyMessageEvent );
    procedure DoSendMessage( AMessage : TBaseMessage );
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    constructor Create;
    destructor Destroy; override;

    procedure AddMessage( AMessage : TBaseMessage );

    property OnMessage : TNotifyMessageEvent read GetOnMessage write SetOnMessage;
  end;

constructor TMessageService.Create;
begin
  inherited Create( False );
  FCS := TCriticalSection.Create;
  FEvent := TEvent.Create( nil, False, False, '' );
  FMessages := TObjectQueue<TBaseMessage>.Create;
end;

destructor Destroy;
begin

  inherited;
  FMessages.Free;
  FEvent.Free;
  FCS.Free;
end;

function TMessageService.GetOnMessage : TNotifyMessageEvent;
begin
  FCS.Enter;
  try
    Result := FOnMessage;
  finally
    FCS.Leave;
  end;
end;

procedure TMessageService.SetOnMessage( const Value : TNotifyMessageEvent );
begin
  FCS.Enter;
  try
    FOnMessage := Value;
  finally
    FCS.Leave;
  end;
end;

procedure TMessageService.AddMessage( AMessage : TBaseMessage );
begin
  FCS.Enter;
  try
    FMessages.Enqueue( AMessage );
    FEvent.SetEvent; // <-- Den MessageService aufwecken
  finally
    FCS.Leave;
  end;
end;

procedure function TMessageService.GetOnMessage : TNotifyMessageEvent;
begin
  FCS.Enter;
  try
    Result := FOnMessage;
  finally
    FCS.Leave;
  end;
end;

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

procedure TMessageService.DoSendMessage( AMessage : TBaseMessage );
var
  LOnMessage : TNotifyMessageEvent;
begin
  LOnMessage := OnMessage;
  if Assigned( LOnMessage ) then
    LOnMessage( Self, AMessage );
end;

procedure TMessageService.Execute;
var
  LMessage : TBaseMessage;
begin
  inherited;
  while not Terminated do
  begin
    FEvent.WaitFor; // Wir warten, bis sich was tut
    if not Terminated then
    begin
      // Nachricht aus der Queue holen
      FCS.Enter;
      try
        LMessage := FMessages.Extract;
        // Wenn noch Nachrichten in der Queue sind, dann den Event wieder setzen
        if FMessages.Count > 0 then
          FEvent.SetEvent;
      finally
        FCS.Leave;
      end;
      // Nachricht versenden
      Synchronize( procedure begin DoSendMessage( LMessage ); end );
      // Nachricht freigeben
      LMessage.Free;

    end;
  end;
Dieser MessageService übernimmt die Verwaltung für die Message-Instanz, liefert diese Message per Synchronize an wen auch immer aus. Das hat aber dann mit dem eigentlichen Thread, der da am arbeiten ist schon nichts mehr zu tun.

Schon ist der Drops gelutscht und jeder macht nur ein wenig und nicht alles oder kreuz und quer durcheinander gewürfelt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr.
Seite 3 von 3     123   

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 by Thomas Breitkreuz