【Delphi】实现程序关闭时自动先关闭线程【20210125更新】

本文介绍了一个用于确保主线程在所有子线程安全终止后关闭的应用程序示例。通过使用TCriticalSection和TList来跟踪活动线程,并重写线程创建和销毁方法,实现了线程的安全管理。
ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

unit Unit1; //测试用

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  uGernericThread;

type
//改为TTestThread = class(TThread)会报内存泄漏,证明线程没有自动释放
  TTestThread = class(TGenericThread)
  public
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TTestThread.Execute;
var
  I: Integer;
begin
  Sleep(Random(1000));
  while not Terminated do
  begin
    for I := 1 to 100000000 do
    begin
      Sqrt(I);
    end;
    sleep(50);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutDown := True;
  Position := poScreenCenter;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  TTestThread.Create;
  TTestThread.Create;
  TTestThread.Create;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 //
end;

end.
unit uGenericThread;  //实现主Form关闭时,程序自动先关闭线程, 然后才关闭主Form
                       //此单元中,线程数>0时重载了主Form的OnCloseQuery事件
interface

uses System.Classes, Generics.Collections, System.SysUtils,
     Winapi.Windows, Vcl.Forms, Winapi.Messages, System.SyncObjs;

type
  TGenericThread = class(TThread)
  private
    class procedure NewCloseQuery(Sender: TObject; var CanClose: Boolean);
  public
    constructor Create(aCreateSuspended: Boolean = False);
    destructor Destroy; override;
  end;

implementation

var
  CritSect: TCriticalSection;
  MainFormClosing: Boolean;
  ThreadList: TList<TThread>;
  OriginalCloseQuery: procedure(Sender: TObject; var CanClose: Boolean) of Object;

class procedure TGenericThread.NewCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  Thread: TThread;
begin
  CritSect.Enter;
    if ThreadList.Count <> 0 then
    begin
      CanClose := False; //还有线程没释放的情况下,暂时不关闭主Form
      MainFormClosing := True;
      for Thread in ThreadList do
      begin
        Thread.Terminate;
      end;
    end;
  CritSect.Leave;
end;

//============================================================================

constructor TGenericThread.Create(aCreateSuspended: Boolean);
begin
  CritSect.Enter;
    if ThreadList.Count = 0 then
    begin   //一旦有线程创建,主Form的OnCloseQuery就使用这里定义的FormCloseQuery
      OriginalCloseQuery := Application.MainForm.OnCloseQuery;
      Application.MainForm.OnCloseQuery := NewCloseQuery;
    end;
    ThreadList.Add(Self);
  CritSect.Leave;

  inherited;
  FreeOnTerminate := True;
end;

destructor TGenericThread.Destroy;
begin
  //在FreeOnTerminate := True的情况下,Destroy的执行实际上是在线程里面进行的
  CritSect.Enter;
    ThreadList.Remove(Self); //对ThreadList的操作需要在临界保护区里完成
    if (ThreadList.Count = 0) then
    begin //一旦线程释放完毕,主Form的OnCloseQuery恢复使用原来定义的FormCloseQuery
      Application.MainForm.OnCloseQuery := OriginalCloseQuery;
      if MainFormClosing then   //线程已经释放完毕,发消息关闭主Form
        PostMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0);
    end;
  CritSect.Leave;

  inherited;
end;

initialization
  MainFormClosing := False;
  ThreadList := TList<TThread>.Create;
  CritSect   := TCriticalSection.Create;

finalization
  ThreadList.Free;
  CritSect.Free;

end.

 

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值