"Pausing" A Thread With A Property
Asked Answered
H

2

6

I have a TThread object and want to be able to start/stop the thread via a button on the main form of the program. I've been looking into ways to do this and so far I have the following ideas:

  1. Terminate and Free the thread when the user clicks stop and create a new one when they click start.
  2. Use sleep to delay the thread (I don't want to do this)
  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.

I'm leaning towards #3. Would setting a boolean property on the TThread object from the main form be threadsafe?

Which of these options, or any better alternative, should I go with? This is my first time using threads so any help is appreciated.

Hanna answered 21/7, 2016 at 23:48 Comment(2)
Recent versions of Delphi don't allow pausing/resuming threads, because the entire design (and concept) was flawed. You should avoid attempting to do so and switch to using signalled events (e.g., TEvent) instead. See the various event types in SyncObjs.Carper
see also #4401671Kinetics
C
10

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;
Cormack answered 22/7, 2016 at 2:18 Comment(2)
Remy, What is SysUtils.Abort; in the CheckPause method used for.Villous
It raises an EAbort exception to immediately terminate the thread (since Execute() does not catch it) the next time CheckPause() is called after Terminate() has been called.Cormack
A
-1

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.

Artair answered 22/7, 2016 at 0:23 Comment(2)
This is a comment to the question, not an answer. Answers contain the relevant information here, in the post itself, with links used only to provide additional reference. Answers should stand on their own, so that they contain value if the off-site location is unavailable for some reason (moved, off-line, or whatever). Link only answers do not do so.Carper
Welcome to Stack Overflow. You have not answered the question. The question requests a recommendation, but you have neglected to provide one. Please edit your answer so that it addresses what the question asks for.Glottochronology

© 2022 - 2024 — McMap. All rights reserved.