“暂停”具有属性的线程

时间:2016-07-21 23:48:44

标签: multithreading delphi critical-section pause tthread

我有一个TThread对象,希望能够通过程序主窗体上的按钮启动/停止线程。我一直在研究如何做到这一点,到目前为止我有以下想法:

  1. 当用户单击“停止”时终止并释放该线程,并在单击“开始”时创建一个新线程。
  2. 使用sleep延迟线程(我不想这样做)
  3. 拥有一个布尔值属性,以确定线程是否暂停。只有在此布尔值为false时,才会执行Execute中的代码。
  4. 我倾向于#3。在主窗体上设置TThread对象的布尔属性是线程安全吗?

    我应该选择哪些选项或更好的选择?这是我第一次使用线程,所以感谢任何帮助。

2 个答案:

答案 0 :(得分:9)

  

1.当用户点击停止时终止并释放该线程,并在点击开始时创建一个新线程。

如果开销很小,这肯定是一种选择。

  

3.具有一个布尔值属性,以确定线程是否暂停。只有当此布尔值为false时,才会执行Execute中的代码。

你可以这样做,但你必须定期检查那个布尔值,如果设置了,那么进入一个等待循环,直到它被清除或线程被发出信号终止。

  

从主窗体设置TThread对象的布尔属性是线程安全吗?

它与调用TThread.Terminate()一样是线程安全的,它只是设置布尔TThread.Terminated属性。

  

我应该选择哪些选项或更好的选择?

我使用选项#4 - 使用信号事件而不是布尔值。例如:

type
  TMyThread = class(TThread)
  private
    FRunEvent, FTermEvent: TEvent;
    FWaitEvents: THandleObjectArray;
    procedure CheckPause;
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    constructor Create; reintroduce;
    destructor Destroy; override;
    procedure Pause;
    procedure Unpause;
  end;

constructor TMyThread.Create;
begin
  inherited Create(False);

  FRunEvent := TEvent.Create(nil, True, True, '');
  FTermEvent := TEvent.Create(nil, True, False, '');

  SetLength(FWaitEvents, 2);
  FWaitEvents[0] := FRunEvent;
  FWaitEvents[1] := FTermEvent;
end;

destructor TMyThread.Destroy;
begin
  FRunEvent.Free;
  FTermEvent.Free;
  inherited;
end;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    // do some work...
    CheckPause;
    // do some more work...
    CheckPause;
    // do some more work...
    CheckPause;
    //...
  end;
end;

procedure TMyThread.TerminatedSet;
begin
  FTermEvent.SetEvent;
end;

procedure TMyThread.CheckPause;
var
  SignaledEvent: THandleObject;
begin
  while not Terminated do
  begin
    case TEvent.WaitForMultiple(FWaitEvents, INFINITE, False, SignaledEvent) of
      wrSignaled: begin
        if SignaledEvent = FRunEvent then Exit;
        Break;
      end;
      wrIOCompletion: begin
        // retry
      end;
      wrError: begin
        RaiseLastOSError;
    end;
  end;
  SysUtils.Abort;
end;

procedure TMyThread.Pause;
begin
  FRunEvent.ResetEvent;
end;

procedure TMyThread.Unpause;
begin
  FRunEvent.SetEvent;
end;

答案 1 :(得分:-1)

在这里查看关于启动和停止线程的维基的维基:http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads

这可以追溯到Delphi 7.它可能适用于更远的版本,但我无法确认早期版本。