Einzelnen Beitrag anzeigen

Edelfix

Registriert seit: 6. Feb 2015
Ort: Stadtoldendorf
248 Beiträge
 
Delphi 12 Athens
 
#5

AW: TThread mit Queue und Events

  Alt 26. Mai 2025, 13:17
Ein Beispiel (ungeprüft):

Hauptformular (Form1)

Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  WorkerThreadUnit;

type
  TForm1 = class(TForm)
    btnStartThread: TButton;
    btnSendData: TButton;
    btnModeNormal: TButton;
    btnModeIgnore: TButton;
    btnModeAlternative: TButton;
    btnStopThread: TButton;
    MemoLog: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnStartThreadClick(Sender: TObject);
    procedure btnSendDataClick(Sender: TObject);
    procedure btnModeNormalClick(Sender: TObject);
    procedure btnModeIgnoreClick(Sender: TObject);
    procedure btnModeAlternativeClick(Sender: TObject);
    procedure btnStopThreadClick(Sender: TObject);
  private
    FWorker: TMyWorkerThread;
    FDataCounter: Integer;
    procedure LogMessage(const Msg: string);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FWorker := nil;
  FDataCounter := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    FWorker.StopThread;
    FWorker.Terminate;
    FWorker.WaitFor;
    FreeAndNil(FWorker);
  end;
end;

procedure TForm1.btnStartThreadClick(Sender: TObject);
begin
  if not Assigned(FWorker) then
  begin
    FWorker := TMyWorkerThread.Create(
      procedure(const Msg: string)
      begin
        LogMessage(Msg);
      end);
    LogMessage('Thread gestartet.');
  end;
end;

procedure TForm1.btnSendDataClick(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    Inc(FDataCounter);
    FWorker.EnqueueData('Nachricht #' + FDataCounter.ToString);
  end;
end;

procedure TForm1.btnModeNormalClick(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    FWorker.SetProcessingMode(0);
    LogMessage('Modus: Normal');
  end;
end;

procedure TForm1.btnModeIgnoreClick(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    FWorker.SetProcessingMode(1);
    LogMessage('Modus: Ignorieren');
  end;
end;

procedure TForm1.btnModeAlternativeClick(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    FWorker.SetProcessingMode(2);
    LogMessage('Modus: Alternative Verarbeitung');
  end;
end;

procedure TForm1.btnStopThreadClick(Sender: TObject);
begin
  if Assigned(FWorker) then
  begin
    FWorker.StopThread;
    FWorker.Terminate;
    FWorker.WaitFor;
    FreeAndNil(FWorker);
    LogMessage('Thread gestoppt.');
  end;
end;

procedure TForm1.LogMessage(const Msg: string);
begin
  TThread.Queue(nil, procedure begin
    MemoLog.Lines.Add(Msg);
  end);
end;

end.
Worker-Thread (WorkerThreadUnit)

Delphi-Quellcode:
unit WorkerThreadUnit;

interface

uses
  System.Classes, System.SysUtils, System.SyncObjs, System.Generics.Collections;

type
  TMyWorkerThread = class(TThread)
  private
    FQueue: TThreadedQueue<string>;
    FTerminateEvent: TEvent;
    FProcessingMode: Integer;
    FModeLock: TCriticalSection;
    FLogProc: TProc<string>;
  protected
    procedure Execute; override;
  public
    constructor Create(LogProc: TProc<string>);
    destructor Destroy; override;

    procedure EnqueueData(const AData: string);
    procedure SetProcessingMode(AMode: Integer);
    procedure StopThread;
  end;

implementation

constructor TMyWorkerThread.Create(LogProc: TProc<string>);
begin
  inherited Create(False);
  FQueue := TThreadedQueue<string>.Create(100);
  FTerminateEvent := TEvent.Create(nil, True, False, '');
  FModeLock := TCriticalSection.Create;
  FLogProc := LogProc;
end;

destructor TMyWorkerThread.Destroy;
begin
  FQueue.Free;
  FTerminateEvent.Free;
  FModeLock.Free;
  inherited;
end;

procedure TMyWorkerThread.EnqueueData(const AData: string);
begin
  FQueue.Enqueue(AData);
end;

procedure TMyWorkerThread.SetProcessingMode(AMode: Integer);
begin
  FModeLock.Acquire;
  try
    FProcessingMode := AMode;
  finally
    FModeLock.Release;
  end;
end;

procedure TMyWorkerThread.StopThread;
begin
  FTerminateEvent.SetEvent;
end;

procedure TMyWorkerThread.Execute;
var
  Data: string;
  Mode: Integer;
begin
  while not Terminated do
  begin
    if FTerminateEvent.WaitFor(0) = wrSignaled then
      Break;

    if FQueue.Dequeue(Data, 100) = TWaitResult.wrSignaled then
    begin
      FModeLock.Acquire;
      try
        Mode := FProcessingMode;
      finally
        FModeLock.Release;
      end;

      case Mode of
        0: FLogProc('Verarbeite: ' + Data);
        1: FLogProc('Ignoriert: ' + Data);
        2: FLogProc('Alternative Verarbeitung: ' + Data);
      end;
    end
    else
    begin
      Sleep(10);
    end;
  end;

  FLogProc('Thread beendet.');
end;

end.
Oder habe ich es falsch verstanden?
  Mit Zitat antworten Zitat