Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Wie erzeugt man ein Event? (https://www.delphipraxis.net/167798-wie-erzeugt-man-ein-event.html)

Medium 19. Apr 2012 15:31

AW: Wie erzeugt man ein Event?
 
Der für mich oftmals entscheidende Vorteil von Messages ist, dass sie eine sehr lose Kopplung darstellen, und "Multicasting" ohne weiteres Zutun geht, da ohnehin an alle Top-Level Fenster verschickt wird. Da liegt aber auch einer der Nachteile: Wenn die verarbeitende Einheit nicht sinnvoll in "Fensternähe" passieren kann, muss man sich manuell ein Handle besorgen und die WndProc bauen.
Sobald Threads im Spiel sind, nehme ich die fast immer zur Kommunikation mit "aussen", vor allem weil man sonst auch gerne mal so Finten bekommt, dass man eine SQL-Connection eher unbemerkt in einem anderen Threadkontext benutzt als sie erstellt wurde (was meist schief geht). Andere Systemresourcen sind da ähnlich empfindlich, und durch die Messages ist der Kontext eindeutig.

Wenn es nicht zu erwarten ist, dass ein Objekt mal Threadkontextübergreifend "quasseln" muss, greife ich aber genau so gerne zu den üblichen Eventhandlern (aka Methodenzeigern). Deren Vorteil liegt am ehesten noch im Übergeben von mehreren Parametern und ohne Rumgecaste. Letztlich ist das Argument "komfortabel bei Asynchronität" das schwerwiegendste bei Messages.

Sir Rufo 19. Apr 2012 21:34

AW: Wie erzeugt man ein Event?
 
Da der TE mit Delphi XE2 arbeitet bietet sich natürlich auch Delphi-Referenz durchsuchenTThread.Queue an als nicht-blockierende Alternative zu Synchronize.
Und der Uwe hat dazu auch einen schönen Artikel auf seiner Seite veröffentlicht, wie man sich sehr elegant die Zwischenvariable schenken kann.

UliBru 20. Apr 2012 09:23

AW: Wie erzeugt man ein Event?
 
Lauter interessante Vorschläge. Ich verwende nun Queue als vielleicht einfachste Lösung. Klar ist mir, dass die Verarbeitung im Main schnell genug sein muss bevor der nächste asynchrone Aufruf kommt. Dafür werkelt eben der Thread ungebremst vor sich hin.

Ich stell mal meine Lösung hier rein. Falls da noch etwas falsch sein sollte wäre ich für Hinweise dankbar. Ansonsten steht es als Muster zur Verfügung.

Im der Main-Unit:
Delphi-Quellcode:
interface

  type
  TMainForm = class(TForm)
  private
    ...
  public
    ...
    myThread: TmyThread;
    buffer: TmyBuffer;
    bufsize: integer;
    procedure OnBufferSwitch(buffer: tmyBuffer; bufidx: Integer);
  end;

implementation

procedure TMainForm.FormCreate(Sender: TObject);
begin
  bufsize := ...;
  buffer := TmyBuffer.Create(bufsize);
  myThread := TmyThread.Create(true);  //erst suspended
  myThread.Buffer := buffer;           //Buffer übergeben
  myThread.FOnEvent := OnBufferSwitch; //Zuweisung Ereignisprozedur nun hier im Main
  myThread.FreeOnTerminate := true;
  myThread.Start;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Terminate;
  buffer.Free;
end;

procedure TMainForm.OnBufferSwitch(bufidx: Integer);
begin
  DoSomething(buffer,bufidx); //Auswertung Datenpuffer
end;
und dann in der Thread-Unit:
Delphi-Quellcode:
interface

type
  TOnBufferSwitch = procedure(bufidx: Integer) of object;

type
  TmyThread = class(TThread)
  private
    fbuffer: tmyBuffer;
    foldbufidx: integer;
    fbufidx: integer;
    FCS: TCriticalSection;
    procedure AsyncBufferSwitch;
  protected
    procedure Execute; override;
  public
    FOnEvent: TOnBufferSwitch;
    property Buffer: tmyBuffer read fbuffer write fbuffer;
    property OnEvent: TOnBufferSwitch read FOnEvent write FOnEvent;
    constructor Create(suspended:boolean); reintroduce;
    destructor Destroy; override;
  end;

implementation

constructor TmyThread.Create(suspended:boolean);
begin
  inherited Create(suspended);
  FCS := TCriticalSection.Create;
end;

destructor TmyThread.Destroy;
begin
  FCS.Free;
  inherited;
end;

procedure TmyThread.Execute;
var oldbufidx: integer;
begin
  FOnEvent := MainForm.OnBufferSwitch; //Zuweisung Ereignisprozedur
  while not(Terminated) do
  begin
    CatchDriverData; //do something
    ...
    FCS.Enter;
    try
      foldbufidx := fbuffer.writebufidx; //aktueller Puffer
      fbuffer.Write(DriverDataArray, count); //inkl. autom. Umschaltung Pufferindex, wenn ein Puffer voll
      fbufidx := fbuffer.writebufidx;    //neuer Pufferindex, falls umgeschaltet
    finally
      FCS.Leave;
    end;
    if bufidx <> oldbufidx then
      Queue(AsyncBufferSwitch);  // <------ hier nun Queue anstelle von Synchronize
    sleep(10);
  end;
end;

procedure TmyThread.AsyncBufferSwitch;
begin
  if Assigned(FOnEvent) then
    FOnEvent((fbufidx+1) and $1);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:34 Uhr.
Seite 2 von 2     12   

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