我有一个button1和一个label1button1单击 时,label1开始在其自己的线程上进行计数。

问题是,当我单击时,我无法停止该线程button2

这是我正在使用的代码:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, System.SyncObjs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private

  public

  end;

{ TMyThread is the class that will handle background work for Label1 }
  MyThread1 = class(TThread)
  private
    count: Integer;
    msg: string;
    stopThread:boolean;
  protected
    procedure Execute; override;
    procedure UpdateUI;
  public
    constructor Create;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ MyThread Constructor }
constructor MyThread1.Create;
begin
  inherited Create(False); // False means it will start right away
  FreeOnTerminate := True; // Free memory when finished
end;

{ Worker Thread for Label1 }
procedure MyThread1.Execute;
var
  i: Integer;
begin
  for i := 1 to 1000 do
  begin
    //Check to see if the was terminated. If so, then exit the for loop.
    if Terminated then
      Exit;

    Sleep(10); // Simulate work (1 second per iteration)
    msg := '# ' + IntToStr(i);
    Synchronize(UpdateUI); // Update UI safely from the main thread
  end;

  Synchronize(UpdateUI);
end;

{ Update the UI for Label1 }
procedure MyThread1.UpdateUI;
begin
  Inc(count);
  Form1.Label1.Text := msg;

  //WHen finished:
  if (count = 1000) then
  begin
    ShowMessage('Thread 1 Finished!');
  end;
end;

{Start the thread when button1 is clicked}
procedure TForm1.Button1Click(Sender: TObject);
begin
  MyThread1.Create; // Create and start the first thread for Label1
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  //Procedure to stop the MyThread1 thread goes here.
end;

end.

我试图停止该线程,但它没有停止。

我无法终止该线程到底是什么问题?


最佳答案
1

您没有使用该stopThread成员,因此请将其删除。您的线程Execute()代码正在查看线程的Terminated属性,因此请调用线程的Terminate()方法。

但是,您button1没有保存它创建的线程对象,因此button2无法访问它。

尝试一些更像这样的事情:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, System.SyncObjs;

type
  MyThread1 = class;

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FMyThread: MyThread1:
    procedure ThreadTerminated(Sender: TObject);
  public
  end;

{ TMyThread is the class that will handle background work for Label1 }
  MyThread1 = class(TThread)
  private
    count: Integer;
    msg: string;
  protected
    procedure Execute; override;
    procedure UpdateUI;
  public
    constructor Create;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ MyThread Constructor }
constructor MyThread1.Create;
begin
  inherited Create(True); // True means it will not start right away
  FreeOnTerminate := True; // Free memory when finished
end;

{ Worker Thread for Label1 }
procedure MyThread1.Execute;
var
  i: Integer;
begin
  for i := 1 to 1000 do
  begin
    //Check to see if the thread was terminated. If so, then exit the for loop.
    if Terminated then
      Break;

    Sleep(10); // Simulate work (1 second per iteration)
    msg := '# ' + IntToStr(i);
    Synchronize(UpdateUI); // Update UI safely from the main thread
  end;

  Synchronize(UpdateUI);
end;

{ Update the UI for Label1 }
procedure MyThread1.UpdateUI;
begin
  Inc(count);
  Form1.Label1.Text := msg;
end;

{Start the thread when button1 is clicked}
procedure TForm1.Button1Click(Sender: TObject);
begin
  if FMyThread <> nil then Exit;
  FMyThread := MyThread1.Create; // Create and start the first thread for Label1
  FMyThread.OnTerminate := ThreadTerminated;
  FMyThread.Start;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  //Procedure to stop the MyThread1 thread goes here.
  if FMyThread <> nil then
    FMyThread.Terminate;
end;

procedure TForm1.ThreadTerminated(Sender: TObject);
begin
  //WHen finished:
  FMyThread := nil; 
  ShowMessage('Thread 1 Finished!');
end;

end.

3

  • 1) FMyThread<>nil 的测试、2) FMyThread:=nil 和 3) FMyThread.Terminate 之间是否存在竞争条件?


    – 

  • 2
    @AndersMelander 不,因为所有这三个操作都是在主线程中完成的。TThread.OnTerminate默认情况下,事件是同步的(您可以覆盖TThread.DoTerminate()以更改这一点)


    – 


  • 是的你是对的。


    –