微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

delphi – 何时手动释放线程

如果我从主线程创建(挂起)线程,如下:
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);
  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.

原文地址:https://www.jb51.cc/delphi/103038.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐