Einzelnen Beitrag anzeigen

Benutzerbild von Björn Ole
Björn Ole

Registriert seit: 10. Jul 2008
166 Beiträge
 
Delphi XE Professional
 
#1

TThreadList - So richtig?

  Alt 2. Okt 2010, 15:11
Delphi-Version: 2010
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
  Mit Zitat antworten Zitat