Delphi的TThread类

Delphi----TThread的使用方法 Delphi----TThread的使用方法TThread的使用方法简述继承的TThread接口具体实现相关补充(TFUN,property) TThread的使用方法 简述 TThread是Delphi的一个线程类,与win32的的系统调用相比,TThread的功能更丰富,对用户而言自由度更高。下面的代码,会针对TThread的继承使用和同步进行展开。 继承的TThread接口 TFun =... 阅读详情

 Delphi的TThread类
http://bigpower.blog.51cto.com/209892/89525
我们常有工作线程和主线程之分,工作线程负责作一些后台操作,比如接收邮件;主线程负责界面上的一些显示。工作线程的好处在某些时候是不言而喻的,你的主界面可以响应任何操作,而背后的线程却在默默地工作。
VCL中,工作线程执行在Execute方法中,你必须从TThread继承一个类并覆盖Execute方法,在这个方法中,所有代码都是在另一个线程中执行的,除此之外,你的线程类的其他方法都在主线程执行,包括构造方法,析构方法,Resume等,很多人常常忽略了这一点。
最简单的一个线程类如下:
TMyThread = class(TThread)
protected 
   procedure Execute; override; 
end; 
在Execute中的代码,有一个技术要点,如果你的代码执行时间很短,像这样,Sleep(1000),那没有关系;如果是这样Sleep (10000),10秒,那么你就不能直接这样写了,须把这10秒拆分成10个1秒,然后判断Terminated属性,像下面这样: 
procedure TMyThread.Execute; 
var
    i: Integer; 
begin 
   for i := 0 to 9 do 
     if not Terminated then 
       Sleep(1000) 
     else
        Break;
end;
这样写有什么好处呢,想想你要关闭程序,在关闭的时候调用MyThread.Free,这个时候线程并没有马上结束,它调用WaitFor,等待 Execute执行完后才能释放。你的程序就必须等10秒以后才能关闭,受得了吗。如果像上面那样写,在程序关闭时,调用Free之后,它顶多再等一秒就会关闭。为什么?答案得去线程类的Destroy中找,它会先调用Terminate方法,在这个方法里面它把Terminated设为True(仅此而已,很多人以为是结束线程,其实不是)。请记住这一切是在主线程中操作的,所以和Execute是并行执行的。既然Terminated属性已为 Ture,那么在Execute中判断之后,当然就Break了,Execute执行完毕,线程类也正常释放。 
或者有人说,TThread可以设FreeOnTerminate属性为True,线程类就能自动释放。除非你的线程执行的任务很简单,不然,还是不要去理会这个属性,一切由你来操作,才能使线程更灵活强大。

接下来的问题是如何使工作线程和主线程很好的通信,很多时候主线程必须得到工作线程的通知,才能做出响应。比如接收邮件,工作线程向服务器收取邮件,收取完毕之后,它得通知主线程收到多少封邮件,主线程才能弹出一个窗口通知用户。
在VCL中,我们可以用两种方法,一种是向主线程中的窗体发送消息,另一种是使用异步事件。第一种方法其实没有第二种来得方便。想想线程类中的OnTerminate事件,这个事件由线程函数的堆栈引起,却在主线程执行。
事实上,真正的线程函数是这个:
function ThreadProc(Thread: TThread): Integer; 
函数里面有Thread.Execute,这就是为什么Execute是在其他线程中执行,该方法执行之后,有如下句: 
Thread.DoTerminate; 
而线程类的DoTerminate方法里面是 
if Assigned(FOnTerminate) then Synchronize(CallOnTerminate); 
显然Synchronize方法使得CallOnTerminate在主线程中执行,而CallOnTerminate里面的代码其实就是: 
if Assigned(FOnTerminate) then FOnTerminate(Self);
只要Execute方法一执行完就发生OnTerminate事件。不过有一点是必须注意,OnTerminate事件发生后,线程类不一定会释放,只有在FreeOnTerminate为True之后,才会Thread.Free。看一下ThreadProc函数就知道。 
依照Onterminate事件,我们可以设计自己的异步事件。 
Synchronize方法只能传进一个无参数的方法类型,但我们的事件经常是要带一些参数的,这个稍加思考就可以得到解决,即在线程类中保存参数,触发事件前先设置参数,再调用异步事件,参数复杂的可以用记录或者类来实现。 
假设这样,上面的代码每睡一秒,线程即向外面引发一次事件,我们的类可以这样设计: 
   TSecondEvent = procedure (Second: Integer) of object;
   TMyThread = class(TThread)
   private
     FSecond: Integer;
     FSecondEvent: TSecondEvent;
     procedure CallSecondEvent;
   protected
     procedure Execute; override;
   public
     property SencondEvent: TSecondEvent read FSecondEvent
       write FSecondEvent;
   end;
{ TMyThread }
procedure TMyThread.CallSecondEvent;
begin
   if Assigned(FSecondEvent) then
     FSecondEvent(FSecond);
end;
procedure TMyThread.Execute;
var
   i: Integer;
begin
   for i := 0 to 9 do
     if not Terminated then
     begin
       Sleep(1000);
       FSecond := i;
       Synchronize(CallSecondEvent);
     end
     else
       Break;
end;
在主窗体中假设我们这样操作线程:
procedure TForm1.Button1Click(Sender: TObject);
begin
   MyThread := TMyThread.Create(true);
   MyThread.OnTerminate :=   ThreadTerminate;
   MyThread.SencondEvent := SecondEvent;
   MyThread.Resume;
end;
procedure TForm1.ThreadTerminate(Sender: TObject);
begin
   ShowMessage('ok');
end;
procedure TForm1.SecondEvent(Second: Integer);
begin
   Edit1.Text := IntToStr(Second);
end;
我们将每隔一秒就得到一次通知并在Edit中显示出来。
现在我们已经知道如何正确使用Execute方法,以及如何在主线程与工作线程之间通信了。但问题还没有结束,有一种情况出乎我的意料之外,即如果线程中有一些资源,Execute正在使用这些资源,而主线程要释放这个线程,这个线程在释放的过程中会释放掉资源。想想会不会有问题呢,两个线程,一个在使用资源,一个在释放资源,会出现什么情况呢, 
用下面代码来说明:
type
   TMyClass = class
   private
     FSecond: Integer;
   public
     procedure SleepOneSecond;
   end;
   TMyThread = class(TThread)
   private
     FMyClass: TMyClass;
   protected
     procedure Execute; override;
   public
     constructor MyCreate(CreateSuspended: Boolean);
     destructor Destroy; override;
   end;
implementation
{ TMyThread }
constructor TMyThread.MyCreate(CreateSuspended: Boolean);
begin
   inherited Create(CreateSuspended);
   FMyClass := TMyClass.Create;
end;
destructor TMyThread.Destroy;
begin
   FMyClass.Free;
   FMyClass := nil;
   inherited;
end;
procedure TMyThread.Execute;
var
   i: Integer;
begin
   for i := 0 to 9 do
     FMyClass.SleepOneSecond;
end;
{ TMyClass }
procedure TMyClass.SleepOneSecond;
begin
   FSecond := 0;
   Sleep(1000);
end;
end.

用下面的代码来调用上面的类:
procedure TForm1.Button1Click(Sender: TObject);
begin
   MyThread := TMyThread.MyCreate(true);
   MyThread.OnTerminate :=   ThreadTerminate;
   MyThread.Resume;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
   MyThread.Free;
end;
先点击Button1创建一个线程,再点击Button2释放该类,出现什么情况呢,违法访问,是的,MyThread.Free时,MyClass被释放掉了 
FMyClass.Free;
FMyClass := nil; 
而此时Execute却还在执行,并且调用MyClass的方法,当然就出现违法访问。对于这种情况,有什么办法来防止呢,我想到一种方法,即在线程类中使用一个成员,假设为FFinished,在Execute方法中有如下的形式: 
FFinished := False; 
try 
//... ...
finally 
FFinished := True;
End; 
接着在线程类的Destroy中有如下形式: 
While not FFinished do 
   Sleep(100); 
MyClass.Free; 

这样便能保证MyClass能被正确释放。

线程是一种很有用的技术。但使用不当,常使人头痛。在优快云论坛上看到一些人问,我的窗口在线程中调用为什么出错,主线程怎么向其他线程发送消息等等,其实,我们在抱怨线程难用时,也要想想我们使用的方法对不对,只要遵循一些正确的使用规则,线程其实很简单。

后记 
上面有一处代码有些奇怪:FMyClass.Free; FMyClass := nil;如果你只写FMyClass.Free,线程类还不会出现异常,即调用FMyClass.SleepOneSecond不会出错。我在主线程中试了下面的代码
MyClass := TMyClass.Create;
    MyClass.SleepOneSecond; 
   MyClass.Free; 
   MyClass.SleepOneSecond; 
同样也不会出错,但关闭程序时就出错了,如果是这样:
MyClass := TMyClass.Create;
    MyClass.SleepOneSecond; 
   MyClass.Free;
    MyThread := TMyThread.MyCreate(true);
    MyThread.OnTerminate :=   ThreadTerminate;
    MyThread.Resume;
    MyClass.SleepOneSecond;
马上就出错。所以这个和线程类无线,应该是Delphi对于堆栈空间的释放规则,我想MyClass.Free之后,该对象在堆栈上空间还是保留着,只是允许其他资源使用这个空间,所以接着调用下面这一句MyClass.SleepOneSecond就不会出错,当程序退出时可能对堆栈作一些清理导致出错。而如果MyClass.Free之后即创建MyThread,大概MyClass的空间已经被MyThread使用,所以再调用 MyClass.SleepOneSecond就出错了。

Delphi语言的多线程编程 Delphi语言的多线程编程不仅可以提高应用程序的性能,也可以提升用户体验。通过合理地创建和管理线程,以及使用适当的同步机制,开发者可以在Delphi中实现高效的并发设计。在进行多线程编程时,我们需要注意数据竞争、死锁和活锁等常见问题,并采取适当的措施加以解决。希望通过本文的讨论,能帮助读者更好地理解和应用Delphi中的多线程编程技术,从而提升自己的开发水平。 阅读详情

相关推荐

Delphi中线程类TThread实现多线程编程2---事件、临界区、Synchronize、WaitFor……

现在开始说明 Synchronize和WaitFor   但是在介绍这两个函数之前,需要先介绍另外两个线程同步技术:事件和临界区 事件(Event)   事件(Event)与Delphi中的事件有所不同。从本质上讲,Event其实就相当于一个全局的布尔变量。它有两个赋值操作:Set和ReSet,相当于把它设置为 True或False。而检查它的值是通过WaitFor操作进行。对应

NickWei的博客 5064

delphi多线程TThread详解

你的程序就必须等10秒以后才能关闭,受得了吗。VCL中,工作线程执行在Execute方法中,你必须从TThread继承一个类并覆盖Execute方法,在这个方法中,所有代码都是在另一个 线程中执行的,除此之外,你的线程类的其他方法都在主线程执行,包括构造方法,析构方法,Resume等,很多人常常忽略了这一点。在优快云论坛上看到一些人问,我的窗口在线程中调用为什么出错,主线程怎么向其他线程发送消息等等,其实,我们在抱怨线程难用时,也要想想我们使用的方法对不对,只要遵循一些正确的使用规则,线程其实很简单。

疯流人物 2584

delphi7 网络高级编程(精品)

本书主要利用delphi7来实现网络编程.适用于不满足仅仅利用DeIph的vcl网络相关组件进行网络程序开发爱好者。

Delphi中的线程类

      .style1 { FONT-WEIGHT: bold; FONT-SIZE: 12px; COLOR: #ff6699}.yjx { BORDER-RIGHT: #f0

牧月天涯(wwwfind)的专栏 1823

Delphi7创建及释放线程实例

Delphi7创建及释放线程实例,里有我加的中文

DELPHI在视窗里执行DOS命令并返回结果.rar

DELPHI在视窗里执行DOS命令并返回结果,测试可用。

delphi多线程TThread类介绍

Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。    线程本质上是进程中一段并发运行的代码。一个进程至少有一个线程,即所谓的主线程。同时还可以有多个子线程。当

9861

DELPHI7 线程自动刷新

线程的自动刷新,内带详细注释,每一行都有注释,方便新手看代码

Delphi中线程类TThread 实现多线程编程

Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。线程本质上是进程中一段并发运行的代码。一个进程至少有一个线程,即所谓的主线程。同时还可以有多个子线程。当一个进程...

weixin_33755554的博客 1597

Delphi中有一个线程类TThread是用来实现多线程编程

Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。

【学习体会】Lighttools8.4.0:设置虚拟相机+仿真结果3D显示

1.设置虚拟相机并渲染视图中的图像 添加球型光源、接收器、cube物体,设置物体表面的光学属性为简单散射

LeonJin的博客 6283

Delphi 实现检测线程类TThread是否结束

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TMY = class(TThread) public ...

weixin_33811961的博客 284

pycharm添加Anaconda解释器显示不出来

因为我之前下载的是pycharm最新版本2024.1的,所以我抱着试一试的心态卸载重装了2021.3.3的,创建新文件的时候立刻就自己识别好了conda环境。就是图中画圈的地方,之前一直显示为python的图标,但是再Python Interpreter后面跟的路径确实是我下载anaconda的地方。另外一种方法就是使用Virtualenv Environment方式配置,但是我的pycharm还是没有识别出conda的图标。首先是这位的方法,先添加系统解释器,再重启,但是我的图标还是python。

2202_75803271的博客 4006

DELPHI 多线程(TThread类的实现)

DELPHI 多线程(TThread类的实现) 之前学习了用API实现,让我们再学习下用DELPHI的TThread类。 先新建一个普通的工程,再新建一个线程类File>>New>>Othre>>Delphi File>Thread Object,取个名字,DELPHI会自动生成一个单元,我们只需往里简单添加功能代码,和在要使用的单元里实例引用即可。 ...

weixin_30251587的博客 266

Circos图审美拯救计划:用TBtools复刻Nature级共线性分析图谱

本文针对Circos图在共线性分析中的审美提升问题,提供了一套基于TBtools的完整优化方案。通过构建和谐的色彩体系、精细控制信息层布局以及模仿顶刊构图逻辑,详细讲解了如何从配色、透明度、标签显示到高级参数设置,将默认图表升级为具有高级学术美感的Nature级图谱,助力研究者提升论文图表质量。

cherry的博客 911

腾讯股票接口API(1)——根据股票代码获取详情

获取股票简要信息,找来找去也没有找到官方的文档,都是复制粘贴的,这里先简单记录一下。 1.简要信息 以贵州茅台为例: http://qt.gtimg.cn/q=s_sh600519 // sh600519是贵州茅台的股票代码,根据自己的关键字拼接URL 可以直接在Android项目中请求,会得到如下一串字符串: v_s_sh600519="1~贵州茅台~600519~2075.95~42.95~2.11~38930~794942~~26078.04~GP-A"; 这里v_s代表简要信息,sh600519

GeofferySun的专栏 6万+

delphi Tthread类代码分析(转载)

Delphi Thread 线程代码分析(转载) Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对 TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编 程的全部,我写此文的目的在于对此作一个补充。 线程本质上是进程中一段并发运行...

weixin_30498921的博客 100

【C#学习记录】如何让界面控件实现自适应布局(Winform)

小伙伴们大家好,我是雷工!在软件界面设计中,客户常常要求设计的界面可以随意缩放,缩放过程中,界面中的按钮等控件也会随着窗体变大缩小自动调整显示位置和尺寸大小。在C#的Winform窗体中如何实现这个效果,下面我们一起学习下。

做有价值的事,积累有价值的笔记! 1万+

转发 Delphi中线程类TThread 实现多线程编程

Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。 线程本质上是进程中一段并发运行的代码。一个进程至少有一个线程,即所谓的主线程。同时还可以有多个子...

weixin_34352449的博客 157

从通用到定制:营销Agent如何跨越数据鸿沟,实现对话SOP的个性化飞跃

从通用到定制:营销Agent如何跨越数据鸿沟,实现对话SOP的个性化飞跃

丨汀、的博客 656

Python 爬虫实战:Boss直聘 Python 岗位招聘数据爬取

本文介绍了一个Python爬虫项目,用于抓取Boss直聘平台的Python岗位招聘数据并进行可视化分析。项目采用requests库发送POST请求,通过抓包分析获取JSON接口,绕过HTML解析直接获取结构化数据。主要内容包括: 接口分析:找到关键POST接口,解析请求头和JSON参数格式 环境准备:安装requests/pandas/matplotlib/pyecharts等依赖库 核心实现: 手动获取登录Cookie 构建请求头和城市代码映射 实现分页抓取职位列表数据 项目特色在于直接解析JSON接口而

u014481728的博客 297

Delphi多线程学习(2):Delphi中的多线程类TThread。

2010-02-22 17:08:46Delphi把多线程相关的API封装在TThread这个类中,可以方便实现多线程运用。首先看下TThread的声明:TThread = class private FHandle: THandle; FThreadID: THandle; FCreateSuspended: Boolean; FTermi

981

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: 将Word嵌入Delphi中
下一篇: 用dll方式封装mdi子窗体
iseekcode
博客等级 码龄18年 36粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值