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

后端 未结 3 1020
遇见更好的自我
遇见更好的自我 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:30

    You really are approaching this problem completely wrong. Code your threads to only do work that you want them to do, and then there will be no need to "reach in from the outside" to control them. You feel the need to control this thread from the outside because it's doing something you don't want it to do -- well then why did you code it to do that in the first place?

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-02-06 15:52

    Using TEvent can solve this problem this is an eg :

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

    Now if i want to kill my thread ,all what i have to do is calling MyThread.Stop than calling MyThread.Free .

    0 讨论(0)
提交回复
热议问题