How do I stop a thread before it's finished running?

后端 未结 3 1019
遇见更好的自我
遇见更好的自我 2021-02-06 15:03

I have a thread called TMyThread and I overrode the Execute procedure like this:

 procedure TMyThread.Execute;
 Begin
     repeat
     //Some Work 
     Sleep(50         


        
3条回答
  •  别跟我提以往
    2021-02-06 15:34

    Your thread's Execute method must regularly check the state of the thread's Terminated property. And if it is True, then the thread Execute method must exit.

    So, a typical Execute method might look like this:

    procedure TMyThread.Execute;
    begin
      while not Terminated do
        DoNextPieceOfWork
    end;
    

    It looks like your thread has its own FActive flag that is performing the same task. The problem with that is that TThread doesn't know about it. So you should get rid of FActive and instead use the built in mechanism.

    When you call Free on the thread it will call Terminate. That sets Terminated to be True. Then it waits for the thread method to exit. That will happen because your thread notices that Terminated is True and quits. And then the thread's destructor can continue and finish the job of tidying up the thread.


    Looking at the code in your answer, it would be better written to make use of the existing Terminate mechanism.

    type
      TMyThread = class(TThread)
      private
        FTerminateEvent: TEvent;
      protected
        procedure Execute; override;
        procedure TerminatedSet; override;
      public
        constructor Create(ACreateSuspended: Boolean);
        destructor Destroy; override;
      end;
    
    constructor TMyThread.Create(ACreateSuspended: Boolean);
    begin
      inherited Create(ACreateSuspended);
      FTerminateEvent := TEvent.Create(nil, True, False, '');
    end;
    
    destructor TMyThread.Destroy;
    begin
      inherited;
      FTerminateEvent.Free;
    end;
    
    procedure TMyThread.TerminatedSet;
    begin
      FTerminateEvent.SetEvent;
    end;
    
    procedure TMyThread.Execute;
    begin
      while not Terminated do
      begin
        // do somthing interesting!
        FTerminateEvent.WaitFor(5000);
      end;
    end;
    

    Now there's no need for a separate Stop method. You can just call Free on the thread. Then Terminate is called. And then TerminatedSet is called. Then the event is signaled. Then Execute terminates. And then the thread can go away.


    Having said that, I'm struggling to think of a scenario where a 5000ms timeout would be the best approach. I don't know why you are doing this, but I'd guess that you are trying to throttle the thread so that it doesn't run hot. You want to avoid a busy loop. That's admirable, but using a fixed timeout is not the way to do it. The way to do it is to wait on a synchronisation event, typically an event. Then when there is more work to be done, the event becomes signaled and your thread wakes up.

提交回复
热议问题