Einzelnen Beitrag anzeigen

Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
934 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: TThread und kein Ende in Sicht...

  Alt 6. Mär 2019, 18:32
Danke für die Tipps und Hinweise.

Bin ein kleines Stück weiter gekommen.

Da ich während des schreibens abgemeldet wurde, dass ganze nocheinmal.

Ich habe den Code ein wenig an die Hinweise angepasst.

Die Thread-Klasse:
Delphi-Quellcode:
  TCustomThread = class(TThread)
  strict private
    Stream : TFileStream;
    StreamSize : Int64;
    ReadSize : Int64;
    iSize : Integer;
  private
    FCancel : Boolean;
    FFileName : string;
    FIsOpen : Boolean;
    FOnLog : TLogEvent;
    FOnProgress : TProgressEvent;
    procedure SetCancel(const Value : Boolean);
    procedure SetFileName(const Value : string);
  protected
    procedure DoLog(Value : string);
    procedure DoProgress;
    procedure Execute; override;
    procedure Extract;
    {$IFDEF VER200}
    procedure Terminate; reintroduce;
    procedure TerminatedSet;
    {$ELSE}
    procedure TerminatedSet; override;
    {$ENDIF}
  public
    constructor Create; reintroduce;
    destructor Destroy; override;

    property Cancel : Boolean read FCancel write SetCancel;
    property FileName : string read FFileName write SetFileName;
    property OnProgress : TProgressEvent read FOnProgress write FOnProgress;
    property OnLog : TLogEvent read FOnLog write FOnLog;
  end;
  
constructor TCustomThread.Create;
begin
  inherited Create(True);
  iSize := 0;
  ReadSize := 0;
  StreamSize := 0;
  FCancel := False;
  FFileName := EmptyStr;
  FIsOpen := False;
end;

destructor TCustomThread.Destroy;
begin
  inherited Destroy;
end;
  
procedure TCustomThread.Execute;
var
  I : Integer;
begin
  if not FIsOpen then
  begin
    Stream := TFileStream.Create(FFileName, fmOpenRead);
    FIsOpen:= Stream.Handle <> INVALID_HANDLE_VALUE;
    if FIsOpen then
    begin
      StreamSize := Stream.Size;
      I := 10;
      while (StreamSize div I) > MaxInteger do
      I := I * 10;
      iSize := StreamSize div I;
    end;
  end;
  Extract;
end;

procedure TCustomThread.Extract;
var
  iRead : Int64;
begin
  if FIsOpen then
  begin
    while (ReadSize <> StreamSize) and (not Terminated) do
    begin
      iRead:= iSize;

      Inc(ReadSize, iRead);

      if (StreamSize - ReadSize) < iSize then
        iSize := StreamSize - ReadSize;

      if Assigned(FOnProgress) then
        Synchronize(DoProgress);

      Sleep(50);

      if (StreamSize = ReadSize) or FCancel then
        Terminate;
    end;
  end;
end;

procedure TCustomThread.TerminatedSet;
begin
  if FIsOpen then
  begin
    Stream.Free;
    FIsOpen := False;
    iSize := 0;
    ReadSize := 0;
    StreamSize := 0;
  end;
end;
Erzeugt, gestartet und gestoppt wird sie so:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  LogMemo.Lines.Clear;

  CT := TCustomThread.Create;
  CT.OnProgress := ProgressEvent;
  CT.OnLog := LogEvent;
  CT.OnTerminate:= TerminateEvent;
end;

procedure TForm1.btnStartClick(Sender: TObject);
begin
  if Assigned(CT) then
  begin
    CT.FileName := EditFile.Text;
    {$IFDEF VER200}
    CT.Resume;
    {$ELSE}
    CT.Start;
    {$ENDIF}
  end;
end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin
  if Assigned(CT) and CT.Started then
    CT.Cancel := true;
end;
Interessant wird es hier:
Delphi-Quellcode:
procedure TForm1.TerminateEvent(Sender : TObject);
begin
  CT.Free;
  Log('TerminateEvent');
end;
Setze ich auf CT.Free einen Breakpoint und steppe rein, geht es zu TCustomThread.Destroy.
Als nächstest wird TCustomThread.TerminatedSet angesprungen und dort ist FIsOpen = False!
Was ja richtig ist, denn laut System.Classes und Log-Ausgabe wird TerminatedSet doch schon vorher
durch Terminate aufgerufen. Warum also der erneute Aufruf von Destroy?

Geändert von Alter Mann ( 6. Mär 2019 um 18:35 Uhr) Grund: Präzisierung der Frage.
  Mit Zitat antworten Zitat