5

我有一个名为 TMyThread 的线程,我像这样覆盖了 Execute 过程:

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

在主窗体中,我有一个名为“销毁我的线程”的按钮。我想销毁我的线程,但问题是我的线程只有在完成工作后才会被销毁。我想销毁我的线程,即使它还没有完成它的工作。我该怎么做呢?

4

3 回答 3

23

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

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

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

看起来您的线程有自己的FActive标志,正在执行相同的任务。问题在于TThread它不知道。因此,您应该摆脱FActive并使用内置机制。

当您调用Free线程时,它将调用Terminate. 那将TerminatedTrue。然后它等待线程方法退出。这会发生,因为您的线程注意到它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终止。然后线程可以消失。


话虽如此,我正在努力想一个 5000 毫秒超时将是最佳方法的场景。我不知道您为什么要这样做,但我猜您正在尝试限制线程以使其不会运行hot。你想避免一个繁忙的循环。这是令人钦佩的,但使用固定超时不是这样做的方法。这样做的方法是等待一个同步事件,通常是一个事件。然后当有更多工作要做时,事件会发出信号并且您的线程会唤醒。

于 2012-12-25T20:50:33.067 回答
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 。

于 2012-12-26T00:18:46.650 回答
1

你真的完全错误地解决了这个问题。将您的线程编码为仅执行您希望它们执行的工作,然后就无需“从外部进入”来控制它们。你觉得有必要从外部控制这个线程,因为它正在做一些你不希望它做的事情——那么你为什么首先要编写代码来做到这一点?

于 2012-12-25T21:34:17.840 回答