"Pausing" 一个线程 属性
"Pausing" A Thread With A Property
我有一个 TThread 对象,希望能够通过程序主窗体上的按钮 start/stop 线程。我一直在研究如何做到这一点,到目前为止我有以下想法:
- 当用户点击停止时终止并释放线程,当他们点击开始时创建一个新线程。
- 使用睡眠来延迟线程(我不想这样做)
- 有一个 属性 是一个布尔值,用于确定线程是否暂停。 Execute 中的代码只有在这个布尔值是 false 时才会发生。
我倾向于#3。在主窗体的 TThread 对象上设置布尔值 属性 是否是线程安全的?
我应该选择这些选项中的哪一个,或者更好的选择?这是我第一次使用线程,因此非常感谢您的帮助。
在此处查看关于启动和停止线程的 Delphi 维基:http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads
这适用于 Delphi 7。它可能适用于更早的版本,但我无法确认更早的版本。
1.Terminate and Free the thread when the user clicks stop and create a new one when they click start.
如果开销很小,这当然是一个选项。
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.
您可以这样做,但您必须定期检查该布尔值,如果已设置,则进入等待循环,直到它被清除或线程收到终止信号。
Would setting a boolean property on the TThread object from the main form be threadsafe?
它与调用 TThread.Terminate()
一样线程安全,它只是设置布尔值 TThread.Terminated
属性.
Which of these options, or any better alternative, should I go with?
我使用选项 #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;
我有一个 TThread 对象,希望能够通过程序主窗体上的按钮 start/stop 线程。我一直在研究如何做到这一点,到目前为止我有以下想法:
- 当用户点击停止时终止并释放线程,当他们点击开始时创建一个新线程。
- 使用睡眠来延迟线程(我不想这样做)
- 有一个 属性 是一个布尔值,用于确定线程是否暂停。 Execute 中的代码只有在这个布尔值是 false 时才会发生。
我倾向于#3。在主窗体的 TThread 对象上设置布尔值 属性 是否是线程安全的?
我应该选择这些选项中的哪一个,或者更好的选择?这是我第一次使用线程,因此非常感谢您的帮助。
在此处查看关于启动和停止线程的 Delphi 维基:http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads
这适用于 Delphi 7。它可能适用于更早的版本,但我无法确认更早的版本。
1.Terminate and Free the thread when the user clicks stop and create a new one when they click start.
如果开销很小,这当然是一个选项。
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.
您可以这样做,但您必须定期检查该布尔值,如果已设置,则进入等待循环,直到它被清除或线程收到终止信号。
Would setting a boolean property on the TThread object from the main form be threadsafe?
它与调用 TThread.Terminate()
一样线程安全,它只是设置布尔值 TThread.Terminated
属性.
Which of these options, or any better alternative, should I go with?
我使用选项 #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;