使用Delphi TThread进行工作

3

这是我第一次尝试使用 Threads,我正在尝试使用一个 Thread 来复制一个目录,以下是我所做的(在阅读了 这篇文章 之后):

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
TMyThread= class(TThread)
  private
    Fsource, FDest: String;
  protected
  public
    constructor Create(Const Source, Dest: string);
    destructor Destroy; override;
    procedure Execute(); override;
  published
end;
var
  Form1: TForm1;
  MT: TMyThread;
implementation

{$R *.dfm}

{ TMyThread }

constructor TMyThread.Create(const Source, Dest: string);
begin
  Fsource:= Source;
  FDest:= Dest;
end;

destructor TMyThread.Destroy;
begin

  inherited;
end;

procedure TMyThread.Execute;
var Dir: TDirectory;
begin
  inherited;
  try
    Dir.Copy(Fsource, FDest);
  except on E: Exception do
    ShowMessage(E.Message);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
MT := TMyThread.Create('SourceFolder', 'DestinationFolder');
try
  MT.Execute;
finally
  MT.Free;
end;
end;

end.

当我点击 Button1 时,出现以下错误信息:

Cannot call Start on a running or suspended thread

这是什么问题?我对线程不是很了解,我甚至尝试过:
MT := TMyThread.Create('SourceFolder', 'DestinationFolder');

3
不要调用 Execute,框架会自动调用。你只需在主线程中执行它。不要在线程中调用 ShowMessage。不能在主线程之外操作GUI。 - David Heffernan
3
除了David指出的之外,你没有调用TThread的任何构造函数。 - nil
3
此外,你应该避免使用全局变量。在 Execute 方法中调用 inherited 没有意义,因为它会覆盖一个抽象方法。不要声明一个类型为 TDirectory 的变量。Copy 方法是一个类方法。使用 TDirectory.Copy。如果你不理解 @nil 的评论,你需要在你的线程类构造函数中添加一个 inherited - David Heffernan
@DavidHeffernan 我应该使用 SetFreeOnTerminate(True); 还是线程会自动释放? - Ilyes
3
如果Thread.FreeOnTerminate := True,那么线程会在运行结束后自动被销毁。否则,你需要保留对该线程的引用并手动销毁它。 - David Heffernan
显示剩余5条评论
1个回答

5
感谢所有帮助提供有用评论的人:

谢谢大家的帮助和支持:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
TMyThread= class(TThread)
  private
    Fsource, FDest: String;
  protected
  public
    constructor Create(Const Source, Dest: string);
    destructor Destroy; override;
    procedure Execute(); override;
  published
end;
var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMyThread }

constructor TMyThread.Create(const Source, Dest: string);
begin
  inherited Create;
  Fsource:= Source;
  FDest:= Dest;
  Self.FreeOnTerminate := True;
end;

destructor TMyThread.Destroy;
begin
  inherited;
end;

procedure TMyThread.Execute;
begin
  try
    TDirectory.Copy(Fsource, FDest);
  except on E: Exception do
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var MT: TMyThread;
begin
MT := TMyThread.Create('Source', 'Destination');
end;

end.

1
最好在线程构造函数中将 FreeOnTerminate 设置为 true,以避免泄漏。并且跳过 MT 变量,因为不允许引用具有 FreeOnTerminate = true 的线程对象。 - LU RD
1
问题在于它对类的消费者施加了限制。另一个选项是创建暂停,然后在外部释放并终止,然后启动线程。 - David Heffernan
或者在构造函数中传递一个布尔值,以指示是否设置FreeOnTerminate。 - LU RD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接