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)