“Pausing” A Thread With A Property

耗尽温柔 提交于 2019-12-03 00:42:40

1.Terminate and Free the thread when the user clicks stop and create a new one when they click start.

This is certainly an option, if the overhead is minimal.

3.Have a property that is a boolean to determine if the thread is paused or not. The code in the Execute will only happen if this boolean is false.

You could do that, but you would have to check that boolean regularly and if set then enter a wait loop until either it is cleared or the thread is signaled to terminate.

Would setting a boolean property on the TThread object from the main form be threadsafe?

It is as thread-safe as calling TThread.Terminate(), which simply sets the boolean TThread.Terminated property.

Which of these options, or any better alternative, should I go with?

I use option #4 - using signaled events instead of booleans. For example:

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;

Check out the wiki for Delphi on starting and stopping threads here: http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads

This is applicable as far back as Delphi 7. It may be applicable farther back, but I cannot confirm earlier versions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!