Cannot terminate threads

痴心易碎 提交于 2019-12-11 01:49:03

问题


I use threads in my project. And I wanna kill and terminate a thread immediately.

sample:

    type
      test = class(TThread)
      private
        { Private declarations }
      protected
        procedure Execute; override;
      end;

    var
     Form1: TForm1;
     a:tthread;

    implementation

    {$R *.dfm}

    procedure test.Execute;
    begin

      Synchronize(procedure begin    
          form1.ProgressBar1.position := 0;
          sleep(5000);
          form1.ProgressBar1.position := 100;    
      end
      );

    end;

   procedure TForm1.btn_startClick(Sender: TObject);
   begin
     a:=test.Create(false);
   end;

   procedure TForm1.btn_stopClick(Sender: TObject);
   begin
     terminatethread(a.ThreadID,1);  //Force Terminate
   end;

But when I click on the btn_stop (after clicking on btn_start), the thread won't stop. So how can stop this thread immediately?

BTW a.terminate; didn't work too.

Thanks.


回答1:


This is a complete misuse of a worker thread. You are delegating all of the thread's work to the main thread, rendering the worker thread useless. You could have used a simple timer instead.

The correct use of a worker thread would look more like this instead:

type
  test = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;
  a: test = nil;

implementation

{$R *.dfm}

procedure test.Execute;
var
  I: integer
begin
  Synchronize(
    procedure begin    
      form1.ProgressBar1.Position := 0;
    end
  );

  for I := 1 to 5 do
  begin
    if Terminated then Exit;
    Sleep(1000);
    if Terminated then Exit;
    Synchronize(
      procedure begin
        Form1.ProgressBar1.Position := I * 20;
      end
    );
  end;

  Synchronize(
    procedure begin
      form1.ProgressBar1.Position := 100;    
    end
  );
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  btn_stopClick(nil);
end;

procedure TForm1.btn_startClick(Sender: TObject);
begin
  if a = nil then
    a := test.Create(False);
end;

procedure TForm1.btn_stopClick(Sender: TObject);
begin
  if a = nil then Exit;
  a.Terminate;
  a.WaitFor;
  FreeAndNil(a);
end;



回答2:


The problem is the thread waits by using Sleep. This method will keep the thread sleeping for the specified time, no matter what happens around it. In order to be able to "break sleep" you should use an event. The code should be changed to this:

procedure test.Execute;
begin
  Synchronize(procedure begin    
      form1.ProgressBar1.position := 0;
  end);
  Event.WaitFor(5000);
  if not IsTerminated then
    Synchronize(procedure begin    
        form1.ProgressBar1.position := 100;    
    end);
end;

The event should be created and destroyed like this:

constructor test.Create(aCreateSuspended: Boolean);
begin
  inherited;
  Event := TSimpleEvent.Create;
end;

destructor test.Destroy;
begin
  FreeAndNil(Event);
  inherited;
end;

In order to stop the thread, the code is:

procedure TForm1.btn_stopClick(Sender: TObject);
begin
  a.Terminate;
end;

But simply calling Terminate won´t signal the Event, so we have to reimplement Terminate:

procedure test.Terminate;
begin
  inherited;
  Event.SetEvent;
end;

Calling SetEvent will signal the event, so it will wake the thread up. The execution continues in the next line, that tests for thread termination and decides to execute the second part of the code or not.



来源:https://stackoverflow.com/questions/18236338/cannot-terminate-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!