gpt4 book ai didi

delphi - 何时手动释放线程

转载 作者:行者123 更新时间:2023-12-03 14:48:15 25 4
gpt4 key购买 nike

如果我从主线程创建一个(挂起的)线程,如下所示:

  with TMyThread.Create(True) do
begin
OnTerminate := ThreadTerminated;
FreeOnTerminate := False;
Start;
end;

实例完成后,我该如何释放该实例? (即执行过程已完成执行 - 假设我已捕获异常)。

这个Proper way of destroying a tthread object链接显示了一种工作正常且有意义的方法(通过 PostMessage 过程)。但是,如果我创建线程并且没有可以调用 PostMessage 过程的表单或其他内容的句柄,该怎么办?例如,我在直接从 TObject 派生的类中创建线程?

TMyClass = class
public
procedure DoSomething;
end;

TMyClass.DoSomething;
begin
with TMyThread.Create(True) do
begin
OnTerminate := ThreadTerminated;
FreeOnTerminate := False;
Start;
end;
end;

那么,我想,如何在不访问表单句柄的情况下释放线程?

谢谢

最佳答案

显然,某个地方必须有对实例化线程的引用。但我可以理解您的愿望:您想要一个永远完成、从不关心的解决方案。

我建议您通过单独的 ThreadController 类来管理线程的存在:

unit Unit2;

interface

uses
Classes, SysUtils, Forms, Windows, Messages;

type
TMyThreadProgressEvent = procedure(Value: Integer;
Proceed: Boolean) of object;

procedure RunMyThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent);

implementation

type
TMyThread = class(TThread)
private
FException: Exception;
FOnProgress: TMyThreadProgressEvent;
FProceed: Boolean;
FValue: Integer;
procedure DoProgress;
procedure HandleException;
procedure ShowException;
protected
procedure Execute; override;
end;

TMyThreadController = class(TObject)
private
FThreads: TList;
procedure StartThread(StartValue: Integer;
OnProgress: TMyThreadProgressEvent);
procedure ThreadTerminate(Sender: TObject);
public
constructor Create;
destructor Destroy; override;
end;

var
FMyThreadController: TMyThreadController;

function MyThreadController: TMyThreadController;
begin
if not Assigned(FMyThreadController) then
FMyThreadController := TMyThreadController.Create;
Result := FMyThreadController
end;

procedure RunMyThread(StartValue: Integer; OnProgress: TMyThreadProgressEvent);
begin
MyThreadController.StartThread(StartValue, OnProgress);
end;

{ TMyThreadController }

constructor TMyThreadController.Create;
begin
inherited;
FThreads := TList.Create;
end;

destructor TMyThreadController.Destroy;
var
Thread: TThread;
begin
while FThreads.Count > 0 do
begin
Thread := FThreads[0]; //Save reference because Terminate indirectly
//extracts the list entry in OnTerminate!
Thread.Terminate; //Indirectly decreases FThreads.Count
Thread.Free;
end;
FThreads.Free;
inherited Destroy;
end;

procedure TMyThreadController.StartThread(StartValue: Integer;
OnProgress: TMyThreadProgressEvent);
var
Thread: TMyThread;
begin
Thread := TMyThread.Create(True);
FThreads.Add(Thread); //Add to list before a call to Resume because once
//resumed, the thread might be gone already!
Thread.FValue := StartValue;
Thread.FOnProgress := OnProgress;
Thread.OnTerminate := ThreadTerminate;
Thread.Resume;
end;

procedure TMyThreadController.ThreadTerminate(Sender: TObject);
begin
FThreads.Extract(Sender);
end;

{ TMyThread }

procedure TMyThread.DoProgress;
begin
if (not Application.Terminated) and Assigned(FOnProgress) then
FOnProgress(FValue, FProceed);
end;

procedure TMyThread.Execute;
begin
try
FProceed := True;
while (not Terminated) and (not Application.Terminated) and FProceed and
(FValue < 20) do
begin
Synchronize(DoProgress);
if not FProceed then
Break;
Inc(FValue);
Sleep(2000);
end;
//In case of normal execution ending, the thread may free itself. Otherwise,
//the thread controller object frees the thread.
if not Terminated then
FreeOnTerminate := True;
except
HandleException;
end;
end;

procedure TMyThread.HandleException;
begin
FException := Exception(ExceptObject);
try
if not (FException is EAbort) then
Synchronize(ShowException);
finally
FException := nil;
end;
end;

procedure TMyThread.ShowException;
begin
if GetCapture <> 0 then
SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
if (FException is Exception) and (not Application.Terminated) then
Application.ShowException(FException)
else
SysUtils.ShowException(FException, nil);
end;

initialization

finalization
FreeAndNil(FMyThreadController);

end.

要运行此示例线程(以 2 秒为间隔从 5 计数到 19)并提供反馈和提前终止的机会,请从主线程调用:

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure MyThreadProgress(Value: Integer; Proceed: Boolean);
end;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
RunMyThread(5, MyThreadProgress);
end;

procedure TForm1.MyThreadProgress(Value: Integer; Proceed: Boolean);
begin
Caption := IntToStr(Value);
end;

该线程会在线程或应用程序终止时自动终止。

也许这个单元对于您的情况来说有点矫枉过正,因为它能够处理多个线程(同一类型),但我认为它回答了您的问题。根据您的喜好进行调整。

此答案的部分来源:NLDelphi.com .

关于delphi - 何时手动释放线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8252804/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com