delphi 线程教学第六节:TList与泛型
unit
uFooList;
interface
uses
Generics
.
Collections;
type
TFooList <T>=
class
(TList<T>)
private
procedure
FreeAllItems;
protected
procedure
FreeItem(Item: T);virtual;
// 子类中需要重载此过程。以确定到底如何释放 Item
// 如果是 Item 是指针,就用 Dispose(Item);
// 如果是 Item 是TObject ,就用 Item.free;
public
destructor
Destroy;override;
procedure
ClearAllItems;
procedure
Lock;
// 给本类设计一把锁。
procedure
Unlock;
end
;
// 定义加入到 List 的 Item 都由 List 来释放。
// 定义释放规则很重要!只有规则清楚了,才不会乱套。
// 通过这样简单的改造, TList 立马好用 N 倍。
implementation
{ TFooList<T> }
procedure
TFooList<T>.ClearAllItems;
begin
FreeAllItems;
Clear;
end
;
destructor
TFooList<T>.Destroy;
begin
FreeAllItems;
inherited
;
end
;
procedure
TFooList<T>.FreeAllItems;
var
Item: T;
begin
for
Item
in
self
do
FreeItem(Item);
end
;
procedure
TFooList<T>.FreeItem(Item: T);
begin
end
;
procedure
TFooList<T>.Lock;
begin
System
.
TMonitor
.
Enter(self);
end
;
procedure
TFooList<T>.Unlock;
begin
System
.
TMonitor
.
Exit(self);
end
;
end
.
unit
uFrmMain;
interface
uses
Winapi
.
Windows, Winapi
.
Messages, System
.
SysUtils, System
.
Variants, System
.
Classes, Vcl
.
Graphics,
Vcl
.
Controls, Vcl
.
Forms, Vcl
.
Dialogs, Vcl
.
StdCtrls, uCountThread, uFooList;
type
TCountThreadList =
Class
(TFooList<TCountThread>)
// 定义一个线程 List
protected
procedure
FreeItem(Item: TCountThread); override;
// 指定 Item 的释放方式。
end
;
TNumList =
Class
(TFooList<
Integer
>);
// 定义一个 Integer List
TFrmMain =
class
(TForm)
memMsg: TMemo;
edtNum: TEdit;
btnWork: TButton;
lblInfo: TLabel;
procedure
FormCreate(Sender: TObject);
procedure
FormDestroy(Sender: TObject);
procedure
btnWorkClick(Sender: TObject);
procedure
FormCloseQuery(Sender: TObject;
var
CanClose:
Boolean
);
private
{ Private declarations }
FNumList: TNumList;
FCountThreadList: TCountThreadList;
FBuff: TStringList;
FBuffIndex:
Integer
;
FBuffMaxIndex:
Integer
;
FWorkedCount:
Integer
;
procedure
DispMsg(AMsg:
string
);
procedure
OnThreadMsg(AMsg:
string
);
function
OnGetNum(Sender: TCountThread):
Boolean
;
procedure
OnCounted(Sender: TCountThread);
procedure
LockCount;
procedure
UnlockCount;
public
{ Public declarations }
end
;
var
FrmMain: TFrmMain;
implementation
{
$R
*.dfm}
{ TFrmMain }
{ TCountThreadList }
procedure
TCountThreadList
.
FreeItem(Item: TCountThread);
begin
inherited
;
Item
.
Free;
end
;
procedure
TFrmMain
.
btnWorkClick(Sender: TObject);
var
s:
string
;
thd: TCountThread;
begin
btnWork
.
Enabled :=
false
;
FWorkedCount :=
0
;
FBuffIndex :=
0
;
FBuffMaxIndex := FNumList
.
Count -
1
;
s :=
'共'
+ IntToStr(FBuffMaxIndex +
1
) +
'个任务,已完成:'
+ IntToStr(FWorkedCount);
lblInfo
.
Caption := s;
for
thd
in
FCountThreadList
do
begin
thd
.
StartThread;
end
;
end
;
procedure
TFrmMain
.
DispMsg(AMsg:
string
);
begin
memMsg
.
Lines
.
Add(AMsg);
end
;
procedure
TFrmMain
.
FormCloseQuery(Sender: TObject;
var
CanClose:
Boolean
);
begin
// 防止计算期间退出
LockCount;
// 请思考,这里为什么要用 LockCount;
CanClose := btnWork
.
Enabled;
if
not
btnWork
.
Enabled
then
DispMsg(
'正在计算,不准退出!'
);
UnlockCount;
end
;
procedure
TFrmMain
.
FormCreate(Sender: TObject);
var
thd: TCountThread;
i:
Integer
;
begin
FCountThreadList := TCountThreadList
.
Create;
// 可以看出用了 List 之后,线程数量指定更加灵活。
// 多个线程在一个 List 中,这个 List 可以理解为线程池。
for
i :=
1
to
3
do
begin
thd := TCountThread
.
Create(
false
);
FCountThreadList
.
Add(thd);
thd
.
OnStatusMsg := self
.
OnThreadMsg;
thd
.
OnGetNum := self
.
OnGetNum;
thd
.
OnCounted := self
.
OnCounted;
thd
.
ThreadName :=
'线程'
+ IntToStr(i);
end
;
FNumList := TNumList
.
Create;
// 构造一组数据用来测试
FNumList
.
Add(
100
);
FNumList
.
Add(
136
);
FNumList
.
Add(
306
);
FNumList
.
Add(
156
);
FNumList
.
Add(
152
);
FNumList
.
Add(
106
);
FNumList
.
Add(
306
);
FNumList
.
Add(
156
);
FNumList
.
Add(
655
);
FNumList
.
Add(
53
);
FNumList
.
Add(
99
);
FNumList
.
Add(
157
);
end
;
procedure
TFrmMain
.
FormDestroy(Sender: TObject);
begin
FNumList
.
Free;
FCountThreadList
.
Free;
end
;
procedure
TFrmMain
.
LockCount;
begin
System
.
TMonitor
.
Enter(btnWork);
end
;
procedure
TFrmMain
.
UnlockCount;
begin
System
.
TMonitor
.
Exit(btnWork);
end
;
procedure
TFrmMain
.
OnCounted(Sender: TCountThread);
var
s:
string
;
begin
LockCount;
// 锁不同的对象,宜用不同的锁。
// 每把锁的功能要单一,锁的粒度要最小化。才能提高效率。
s := Sender
.
ThreadName +
':'
+ IntToStr(Sender
.
Num) +
'累加和为:'
;
s := s + IntToStr(Sender
.
Total);
OnThreadMsg(s);
inc(FWorkedCount);
s :=
'共'
+ IntToStr(FBuffMaxIndex +
1
) +
'个任务,已完成:'
+ IntToStr(FWorkedCount);
TThread
.
Synchronize(
nil
,
procedure
begin
lblInfo
.
Caption := s;
end
);
if
FWorkedCount >= FBuffMaxIndex +
1
then
begin
TThread
.
Synchronize(
nil
,
procedure
begin
DispMsg(
'已计算完成'
);
btnWork
.
Enabled :=
true
;
// 恢复按钮状态。
end
);
end
;
UnlockCount;
end
;
function
TFrmMain
.
OnGetNum(Sender: TCountThread):
Boolean
;
begin
// 将多个线程访问 FNumList 排队。
FNumList
.
Lock;
try
if
FBuffIndex > FBuffMaxIndex
then
begin
result :=
false
;
end
else
begin
Sender
.
Num := FNumList[FBuffIndex];
result :=
true
;
inc(FBuffIndex);
end
;
finally
FNumList
.
Unlock;
end
;
end
;
procedure
TFrmMain
.
OnThreadMsg(AMsg:
string
);
begin
TThread
.
Synchronize(
nil
,
procedure
begin
DispMsg(AMsg);
end
);
end
;
end
.
delphi 线程教学第六节:TList与泛型的更多相关文章
- delphi 线程教学第五节:多个线程同时执行相同的任务
第五节:多个线程同时执行相同的任务 1.锁 设,有一个房间 X ,X为全局变量,它有两个函数 X.Lock 与 X.UnLock; 有如下代码: X.Lock; 访问资源 P; ...
- delphi 线程教学第四节:多线程类的改进
第四节:多线程类的改进 1.需要改进的地方 a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...
- delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...
- delphi 线程教学第二节:在线程时空中操作界面(UI)
第二节:在线程时空中操作界面(UI) 1.为什么要用 TThread ? TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...
- delphi 线程教学第一节:初识多线程
第一节:初识多线程 1.为什么要学习多线程编程? 多线程(多个线程同时运行)编程,亦可称之为异步编程. 有了多线程,主界面才不会因为耗时代码而造成“假死“状态. 有了多线程,才能使多个任务同时 ...
- delphi 线程教学第一节:初识多线程(讲的比较浅显),还有三个例子
http://www.cnblogs.com/lackey/p/6297115.html 几个例子: http://www.cnblogs.com/lackey/p/5371544.html
- delphi 线程教学第三节:设计一个有生命力的工作线程
第三节:设计一个有生命力的工作线程 创建一个线程,用完即扔.相信很多初学者都曾这样使用过. 频繁创建释放线程,会浪费大量资源的,不科学. 1.如何让多线程能多次被复用? 关键是不让代码退出 ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环
http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...
随机推荐
- spring data redis template GenericJackson2JsonRedisSerializer的使用
配置 <!-- redis template definition --> <bean id="myRedisTemplate" class="org. ...
- python虚拟环境--virtualenv
virtualenv 是一个创建隔绝的Python环境的工具.virtualenv创建一个包含所有必要的可执行文件的文件夹,用来使用Python工程所需的包. 安装 pip install virtu ...
- Hibernate(十):n-n关联关系
背景: 在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于JAVA分类.Hibernate分类. 因此,我们在hibernate的学习文章系列中,需要学会如何使用hibernat ...
- AngularJS 全局scope与指令 scope通信
在项目开发时,全局scope 和 directive本地scope使用范围不够清晰,全局scope与directive本地scope通信掌握的不够透彻,这里对全局scope 和 directive本地 ...
- 【基础】在css中绘制三角形及相关应用
简言 本文简要阐述了用CSS边框的方法在页面上绘制三角形,包括几种典型的三角形绘制,还介绍了几个简单的应用场景.利用边框绘制三角形方法只是众多方案中的一种,大家根据项目实际,选用最适宜项目的方案. 1 ...
- Java面试题—初级(5)
41.a.hashCode() 有什么用?与 a.equals(b) 有什么关系? hashCode() 方法对应对象整型的 hash 值.它常用于基于 hash 的集合类,如 Hashtable.H ...
- NodeJS技巧
1. 获取程序执行时间 // 打印程序执行时间 console.time() // some functions console.timeEnd() 2. 将函数异步化 setTimeout(() = ...
- 【linux之crontab,启动】
一.计划任务 atd at命令发布的任务计划 一次性的任务计划 at time ctrl+d 提交 time: 1.绝对时间:12:00 2.相对时间:+8 3.模糊时间:noon midnight ...
- 空间搜索(圆范围)中Geohash编码方案和网格编码方案对比探讨
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 多个项目中实现范围(圆)搜索的方案为:依赖库表中的X和Y字段构 ...
- [Awson原创]洪水(flood)
Description Awson是某国际学校信竞组的一只菜鸡.今年,该市发生了千年难遇的洪水.被监禁在学校的Awson不甘怠堕,想将自己投入到公益服务事业中去.这天,他偷了H老师的小电驴,偷偷地溜出 ...