Heyho,
ich benutze gerade zum ersten Mal eine ThreadList und wollte fragen, ob ich damit richtig umgehe. Szenario: Ich habe einen TItemThread, der auf Items aus dem Hauptthread wartet. Der Hauptthread kann über TItemThread.AddItem beliebig viele Items der Liste hinzufügen und anschließend TItemThread.WorkItems aufrufen, damit die Items abgearbeitet werden.
Jetzt bin ich mir aber noch unsicher, was passiert, wenn AddItem und WorkItems aufgerufen wird, während der Thread noch am abarbeiten alter Items ist.
Aber ich poste am besten mal den Code:
Delphi-Quellcode:
{ MainForm }
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FItemThread: TItemThread;
end;
{...}
procedure TForm1.FormCreate(Sender: TObject);
begin
FItemThread := TItemThread.Create(false);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FItemThread.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FItemThread.AddItem('"DatenDaten"');
FItemThread.AddItem('"DatenDatenDaten"');
FItemThread.WorkItems;
FItemThread.AddItem('"DatenDatenDatenDatenDaten"');
FItemThread.AddItem('"Daten"');
FItemThread.AddItem('"Daten"');
FItemThread.WorkItems;
end;
Delphi-Quellcode:
{ ItemThread }
type
TItemThread =
class(TThread)
private
FItems: TThreadList;
FWorkEvent: THandle;
FTerminateEvent: THandle;
public
constructor Create(CreateSuspended: boolean);
destructor Destroy;
override;
procedure AddItem(
const AItem:
string);
procedure WorkItems;
procedure Execute;
override;
end;
{...}
constructor TItemThread.Create(CreateSuspended: boolean);
begin
inherited;
FItems := TThreadList.Create;
FWorkEvent := CreateEvent(
nil, true, false,
nil);
FTerminateEvent := CreateEvent(
nil, true, false,
nil);
end;
destructor TItemThread.Destroy;
begin
FItems.Free;
SetEvent(FTerminateEvent);
// WaitForMultipleObjects aufwecken und while-Schleife verlassen
CloseHandle(FWorkEvent);
CloseHandle(FTerminateEvent);
inherited;
end;
procedure TItemThread.AddItem(
const AItem:
string);
var
List: TList;
begin
List := FItems.LockList;
try
List.Add(PChar(AItem));
finally
FItems.UnlockList;
end;
end;
procedure TItemThread.WorkItems;
begin
// Thread benachrichtigen, dass Liste abgearbeitet werden soll
SetEvent(FWorkEvent);
end;
procedure TItemThread.Execute;
var
Events:
Array[0..1]
of THandle;
bListEmpty: boolean;
List: TList;
Item: PChar;
begin
Events[0] := FWorkEvent;
Events[1] := FTerminateEvent;
while not Terminated
do
begin
case WaitForMultipleObjects(Length(Events), @Events, false, INFINITE) - WAIT_OBJECT_0
of
0:
// Liste abarbeiten
begin
repeat
// erstes Item holen und aus der Liste löschen
List := FItems.LockList;
try
Item := List[0];
List.Delete(0);
bListEmpty := List.Count = 0;
finally
FItems.UnlockList;
end;
Sleep(500);
// Mit dem Item arbeiten
Synchronize(
{ GUI aktualisieren } );
until Terminated
or bListEmpty;
// ...bis beendet oder Liste leer
ResetEvent(FWorkEvent);
// Event für WaitForMultipleObjects wieder zurücksetzen
end;
1:
// Beenden
begin
Terminate;
end;
end;
end;
end;
Mir geht es insbesondere um die Execute Methode. Kann da was schieflaufen?
Wird der Thread in jedem Fall sauber beendet?
Und stimmt es, dass es einen Deadlock geben kann,
wenn ich in dem repeat..until ein Synchronize aufrufe?
Danke, Björn