【问题标题】:Working with Delphi TThread使用 Delphi TThread
【发布时间】:2018-01-31 10:15:17
【问题描述】:

这是第一次尝试使用Threads,我正在尝试使用Thread 复制目录,所以这就是我所做的(阅读后this post ):

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 时,我收到以下错误消息:

无法在正在运行或挂起的线程上调用 Start

这里有什么问题?我对线程不太了解,我什至尝试过:

MT := TMyThread.Create('SourceFolder', 'DestinationFolder');

【问题讨论】:

  • 线程与主程序并行运行。这意味着 Thread.Execute 与您的主程序异步运行,因此您的“免费”语句(尝试)在线程有机会运行之前将其销毁 - 因此您的消息
  • 不要打电话给Execute。框架就是这样做的。您只是在主线程中执行它。不要从线程调用ShowMessage。不能在主线程之外做 GUI。
  • 除了大卫指出的,你没有调用TThread的任何构造函数。
  • 此外,您确实应该避免使用全局变量。在你的Execute 中调用inherited 没有什么意义,因为它覆盖了一个抽象方法。并且不要声明TDirectory 类型的变量。 Copy 方法是一个类方法。使用TDirectory.Copy。如果你不理解@nil 的注释,你需要在你的线程类构造函数中添加一个inherited
  • Thread.FreeOnTerminate := True,否则你需要保留引用并自己销毁它。

标签: multithreading delphi


【解决方案1】:

感谢所有帮助 cmets 的人:

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.

【讨论】:

  • 您最好在线程构造函数中将FreeOnTerminate 设置为 true 以避免泄漏。并跳过MT 变量,因为不允许使用 FreeOnTerminate = true 引用线程对象。
  • 这样做的问题是它限制了类的消费者。另一种选择是创建挂起,然后在从外部终止时释放,然后启动线程。
  • 或者通过构造函数传递一个布尔值来判断是否设置FreeOnTerminate。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
相关资源
最近更新 更多