Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Pausing" A Thread With A Property

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.

like image 280
user1970794 Avatar asked Jul 21 '16 23:07

user1970794


People also ask

How do you pause a thread execution?

Thread. sleep() method can be used to pause the execution of current thread for specified time in milliseconds.

Can you pause a thread in c#?

To pause a thread in C#, use the sleep() method.

Does thread sleep block the thread?

Sleep method causes the current thread to immediately block for the number of milliseconds or the time interval you pass to the method, and yields the remainder of its time slice to another thread. Once that interval elapses, the sleeping thread resumes execution. One thread cannot call Thread. Sleep on another thread.

What happens when a thread finishes execution?

So when does a thread finish? It happens in one of two cases: all instructions in the Runnable are executed. an uncaught exception is thrown from the run method.


1 Answers

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;
like image 194
Remy Lebeau Avatar answered Sep 22 '22 07:09

Remy Lebeau