如何在线程完成运行之前停止?

时间:2012-12-25 20:47:05

标签: multithreading delphi

我有一个名为TMyThread的线程,我像这样覆盖执行程序:

 procedure TMyThread.Execute;
 Begin
     repeat
     //Some Work 
     Sleep(5000);
     //Some Work 2;
     Sleep(5000); 
     until FActive=False
 End;

在主窗体中,我有一个名为'Destroy My Thread'的按钮。我想破坏我的线程,但问题是我的线程只有在完成其工作时才会被销毁。我想破坏我的线程,即使它还没有完成它的工作。我该怎么做?

3 个答案:

答案 0 :(得分:22)

您的线程的Execute方法必须定期检查线程的Terminated属性的状态。如果它是True,那么线程Execute方法必须退出。

因此,典型的Execute方法可能如下所示:

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

看起来您的线程有自己的FActive标志执行相同的任务。问题是TThread不知道它。所以你应该摆脱FActive而不是使用内置机制。

当您在主题上致电Free时,它会调用Terminate。这会将Terminated设置为True。然后它等待线程方法退出。这将发生,因为您的帖子注意到TerminatedTrue并退出。然后线程的析构函数可以继续并完成整理线程的工作。


查看答案中的代码,最好使用现有的Terminate机制编写。

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;

现在不需要单独的Stop方法。你可以在线程上调用Free。然后调用Terminate。然后调用TerminatedSet。然后发出事件信号。然后Execute终止。然后线程可以消失。


话虽如此,我很难想象5000ms超时是最好的方法。我不知道你为什么要这样做,但我猜你正在试图限制线程,以便它不会运行 hot 。你想避免繁忙的循环。这是令人钦佩的,但使用固定超时不是这样做的方法。这样做的方法是等待同步事件,通常是事件。然后,当还有更多工作要做时,事件就会发出信号并且你的线程会被唤醒。

答案 1 :(得分:2)

使用TEvent可以解决这个问题 这是一个例如:

  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;

现在如果我要杀死我的线程,我所要做的就是调用MyThread.Stop而不是调用MyThread.Free。

答案 2 :(得分:1)

你真的正在接近这个问题。将您的线程编码为只做您希望他们做的工作,然后就不需要“从外部进入”来控制它们。你觉得有必要从外面控制这个线程,因为它正在做你不想要它做的事情 - 那么你为什么要编写它来做到这一点?