Einzelnen Beitrag anzeigen

Medium

Registriert seit: 23. Jan 2008
3.679 Beiträge
 
Delphi 2007 Enterprise
 
#8

AW: Wie erzeugt man ein Event?

  Alt 19. Apr 2012, 12:42
So konterkarierst du allerdings die Nebenläufigkeit, da der Thread für die Dauer die der Handler braucht ja steht, und der Buffer-Flip nicht mehr nötig wäre. Sauberer und mehr in deinem Sinne wären Fensternachrichten, die asynchron via PostMessage() möglich sind. Gerüst:

Delphi-Quellcode:
unit uDataThread;
const
  WM_BUFFERFLIP = WM_USER + 1234;

type
  TDataThread = class(TThread)
  private
    FHandlerHanlde: HWND;
    Buffer1, Buffer2, CurrentBuffer: TMyBufferType;
    Buffer1CS, Buffer2CS, CurrentCS: TCriticalSection;
  protected
    procedure Execute; override;
  public
    constructor Create(aHandlerHandle: HWND);
  end;

implementation

constructor TDataThread.Create(aHandlerHandle: HWND);
begin
  inherited Create(false);
  FHandlerHandle := aHandlerHandle;
end;

procedure TDataThread.Execute;
begin
  repeat
    CurrentCS.Enter;
    try
      // Do things with CurrentBuffer
    finally
      CurrentCS.Leave;
    end;

    if DoBufferFlip then
    begin
      PostMessage(FHandlerHandle, WM_BUFFERFLIP, Integer(CurrentBuffer), Integer(CurrentCS));
      FlipBuffersAndCriticalSections;
    end;
  until Terminated;
end;

{-------------------------------------------}
unit uMainForm;

uses
  uDataThread;

type
  TMainForm = class(TForm)
  private
    FDataThread: TDataThread;
    procedure BufferHandler(var Msg: TMessage); message WM_BUFFERFLIP;
  public
  end;

implementation

procedure TMainForm.BufferHandler(var Msg: TMessage);
begin
  TCriticalSection(Msg.WParam).Enter;
  try
    DoSomethingWithBuffer(TMyBufferType(Msg.LParam));
  finally
    TCriticalSection(Msg.WParam).Leave;
  end;
end;
Die CriticalSections sind dann wichtig, wenn der Handler länger braucht als das Befüllen eines Buffers, gehören aber auch zum "guten Ton". Ich persönlich würde sogar noch einen Schritt weiter gehen, und eine Liste von Buffern machen. Fertige werden vom Thread an diese gehängt und das MainForm via PostMessage() darüber informiert. Der Handler schnappt sich dann immer den ältesten Buffer, tut was er damit tun soll, und kümmert sich um die Freigabe sowie Löschung aus der Liste. Idealerweise schaut der dann grob so aus:
Delphi-Quellcode:
  while DataThread.BufferList.Count>0 do
  begin
    DoStuffWithBuffer(DataThread.BufferList[0]); // muss nicht synchronisiert werden, da der Thread diesen Buffer nicht mehr anfasst, und in der Liste nur hinten Added
    DataThread.ListCS.Enter;
    try
      DataThread.BufferList.Delete(0); // sollte hingegn doch gesynced werden, weil dabei Daten in der Liste verschoben werden, was sich bei einem parallelen Add() im Thread schlecht macht (TList verwendet intern Arrays, es ist keine einfache Linked-List.)
    finally
      DataThread.ListCS.Leave;
    end;
  end;
Hier muss also nur noch das Adden und Deleten in der Liste duch eine CS gesichert werden, und man könnte im Thread auch mehrere Buffer in die Liste werfen bevor man die Verarbeitung im MainForm anstößt. Zudem hat man so eine handliche Queue, die Phasen großem Buffer-Aufkommens flexibel puffert, und der Handler kann nach und nach alles abarbeiten wenn Zeit dafür ist.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat