使用属性“暂停”线程
Posted
技术标签:
【中文标题】使用属性“暂停”线程【英文标题】:"Pausing" A Thread With A Property 【发布时间】:2016-11-25 17:54:32 【问题描述】:我有一个 TThread 对象,并希望能够通过程序主窗体上的按钮启动/停止线程。我一直在研究如何做到这一点,到目前为止,我有以下想法:
-
当用户单击停止时终止并释放线程,并在用户单击开始时创建一个新线程。
使用 sleep 来延迟线程(我不想这样做)
有一个布尔属性来确定线程是否暂停。 Execute 中的代码仅在此布尔值为 false 时才会发生。
我倾向于#3。在主窗体中为 TThread 对象设置布尔属性是否是线程安全的?
我应该选择这些选项中的哪一个或更好的选择?这是我第一次使用线程,因此非常感谢您的帮助。
【问题讨论】:
最新版本的 Delphi 不允许暂停/恢复线程,因为整个设计(和概念)存在缺陷。您应该避免尝试这样做,而是改用信号事件(例如 TEvent)。查看 SyncObjs 中的各种事件类型。 另见***.com/questions/4401171/… 【参考方案1】:1.用户点击停止时终止并释放线程,点击开始时创建一个新线程。
如果开销很小,这当然是一种选择。
3. 有一个布尔属性来确定线程是否暂停。 Execute 中的代码仅在此布尔值为 false 时才会发生。
您可以这样做,但您必须定期检查该布尔值,如果设置,则进入等待循环,直到它被清除或线程被发出终止信号。
在主窗体中为 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;
【讨论】:
Remy,SysUtils.Abort;
在CheckPause
方法中的用途是什么。
它会引发一个EAbort
异常以立即终止线程(因为Execute()
没有捕获它)下次在调用Terminate()
之后调用CheckPause()
。【参考方案2】:
在此处查看有关 Delphi 启动和停止线程的 wiki:http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads
这适用于 Delphi 7。它可能适用于更早的版本,但我无法确认早期版本。
【讨论】:
这是对问题的评论,而不是答案。答案包含此处的相关信息,在帖子本身中,链接仅用于提供额外的参考。答案应该独立存在,以便在场外位置由于某种原因(移动、离线或其他原因)不可用时包含价值。仅链接答案不这样做。 欢迎来到 Stack Overflow。你还没有回答这个问题。该问题要求提供建议,但您忽略了提供建议。请edit您的答案,以便它解决问题的要求。以上是关于使用属性“暂停”线程的主要内容,如果未能解决你的问题,请参考以下文章