delphi 线程教学第五节:多个线程同时执行相同的任务
X
.
Lock;
访问资源 P;
X
.
Unlock;
unit
uCountThread;
interface
uses
uFooThread;
type
TCountThread =
class
;
TOnGetNum =
function
(Sender: TCountThread):
boolean
of
object
;
//获取 Num 事件。
TOnCounted =
procedure
(Sender: TCountThread)
of
object
;
TCountThread =
class
(TFooThread)
private
procedure
Count;
procedure
DoOnCounted;
function
DoOnGetNum:
boolean
;
public
procedure
StartThread; override;
public
Num:
integer
;
Total:
integer
;
OnCounted: TOnCounted;
OnGetNum: TOnGetNum;
ThreadName:
string
;
end
;
implementation
{ TCountThread }
procedure
TCountThread
.
Count;
var
i:
integer
;
begin
// 注意多线程不适合打断点调试。
// 因为一旦在 IDE 中断后,状态全乱了。
// 可以写 Log 或用脑袋想,哈哈。
if
DoOnGetNum
then
// 获取参数 Num
begin
Total :=
0
;
if
Num >
0
then
for
i :=
1
to
Num
do
begin
Total := Total + i;
sleep(
5
);
//嫌慢就删掉此句。
end
;
DoOnCounted;
// 引发 OnCounted 事件,告知调用者。
ExecProcInThread(Count);
// 上节说到在线程时空里执行本句。
end
;
end
;
procedure
TCountThread
.
DoOnCounted;
begin
if
Assigned(OnCounted)
then
OnCounted(self);
end
;
function
TCountThread
.
DoOnGetNum:
boolean
;
begin
result :=
false
;
if
Assigned(OnGetNum)
then
result := OnGetNum(self);
end
;
procedure
TCountThread
.
StartThread;
begin
inherited
;
ExecProcInThread(Count);
// 把 Count 过程塞到线程中运行。
end
;
end
.
unit
uFrmMain;
interface
uses
Winapi
.
Windows, Winapi
.
Messages, System
.
SysUtils, System
.
Variants, System
.
Classes,
Graphics,
Vcl
.
Controls, Vcl
.
Forms, Vcl
.
Dialogs, Vcl
.
StdCtrls, uCountThread;
type
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 }
FCo1, FCo2, FCo3: TCountThread;
// 定义了3个线程实例
// 以后章节将讲解采用 List 容器来装线程实例。
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
LockBuffer;
procedure
UnlockBuffer;
procedure
LockCount;
procedure
UnlockCount;
public
{ Public declarations }
end
;
var
FrmMain: TFrmMain;
implementation
{
$R
*.dfm}
{ TFrmMain }
procedure
TFrmMain
.
btnWorkClick(Sender: TObject);
var
s:
string
;
begin
btnWork
.
Enabled :=
false
;
FWorkedCount :=
0
;
FBuffIndex :=
0
;
FBuffMaxIndex := FBuff
.
Count -
1
;
s :=
'共'
+ IntToStr(FBuffMaxIndex +
1
) +
'个任务,已完成:'
+ IntToStr(FWorkedCount);
lblInfo
.
Caption := s;
FCo1
.
StartThread;
FCo2
.
StartThread;
FCo3
.
StartThread;
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);
begin
FCo1 := TCountThread
.
Create(
false
);
FCo1
.
OnStatusMsg := self
.
OnThreadMsg;
FCo1
.
OnGetNum := self
.
OnGetNum;
FCo1
.
OnCounted := self
.
OnCounted;
FCo1
.
ThreadName :=
'线程1'
;
FCo2 := TCountThread
.
Create(
false
);
FCo2
.
OnStatusMsg := self
.
OnThreadMsg;
FCo2
.
OnGetNum := self
.
OnGetNum;
FCo2
.
OnCounted := self
.
OnCounted;
FCo2
.
ThreadName :=
'线程2'
;
FCo3 := TCountThread
.
Create(
false
);
FCo3
.
OnStatusMsg := self
.
OnThreadMsg;
FCo3
.
OnGetNum := self
.
OnGetNum;
FCo3
.
OnCounted := self
.
OnCounted;
FCo3
.
ThreadName :=
'线程3'
;
FBuff := TStringList
.
Create;
// 构造一组数据用来测试
FBuff
.
Add(
'100'
);
FBuff
.
Add(
'136'
);
FBuff
.
Add(
'306'
);
FBuff
.
Add(
'156'
);
FBuff
.
Add(
'152'
);
FBuff
.
Add(
'106'
);
FBuff
.
Add(
'306'
);
FBuff
.
Add(
'156'
);
FBuff
.
Add(
'655'
);
FBuff
.
Add(
'53'
);
FBuff
.
Add(
'99'
);
FBuff
.
Add(
'157'
);
end
;
procedure
TFrmMain
.
FormDestroy(Sender: TObject);
begin
FCo1
.
Free;
FCo2
.
Free;
FCo3
.
Free;
end
;
procedure
TFrmMain
.
LockBuffer;
begin
System
.
TMonitor
.
Enter(FBuff);
// System 是单元名。因为 TMonitor 在 Forms 中也有一个相同的名字。
// 同名的类与函数,就要在前面加单元名称以示区别。
end
;
procedure
TFrmMain
.
LockCount;
begin
// 任意一个 TObject 就行,所以我用了 btnWork
System
.
TMonitor
.
Enter(btnWork);
end
;
procedure
TFrmMain
.
OnCounted(Sender: TCountThread);
var
s:
string
;
begin
LockCount;
// 此处亦可以用 LockBuffer
// 但是,锁不同的对象,宜用不同的锁。
// 每把锁的功能要单一,锁的粒度要最小化。才能提高效率。
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
LockBuffer;
// 将多个线程访问 FBuff 排队。
try
if
FBuffIndex > FBuffMaxIndex
then
begin
result :=
false
;
end
else
begin
Sender
.
Num := StrToInt(FBuff[FBuffIndex]);
result :=
true
;
inc(FBuffIndex);
end
;
finally
UnlockBuffer;
end
;
end
;
procedure
TFrmMain
.
OnThreadMsg(AMsg:
string
);
begin
TThread
.
Synchronize(
nil
,
procedure
begin
DispMsg(AMsg);
end
);
end
;
procedure
TFrmMain
.
UnlockBuffer;
begin
System
.
TMonitor
.
Exit(FBuff);
end
;
procedure
TFrmMain
.
UnlockCount;
begin
System
.
TMonitor
.
Exit(btnWork);
end
;
end
.
delphi 线程教学第五节:多个线程同时执行相同的任务的更多相关文章
- delphi 线程教学第六节:TList与泛型
第六节: TList 与泛型 TList 是一个重要的容器,用途广泛,配合泛型,更是如虎添翼. 我们先来改进一下带泛型的 TList 基类,以便以后使用. 本例源码下载(delphi XE8版本) ...
- delphi 线程教学第四节:多线程类的改进
第四节:多线程类的改进 1.需要改进的地方 a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...
- delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...
- delphi 线程教学第二节:在线程时空中操作界面(UI)
第二节:在线程时空中操作界面(UI) 1.为什么要用 TThread ? TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...
- delphi 线程教学第一节:初识多线程
第一节:初识多线程 1.为什么要学习多线程编程? 多线程(多个线程同时运行)编程,亦可称之为异步编程. 有了多线程,主界面才不会因为耗时代码而造成“假死“状态. 有了多线程,才能使多个任务同时 ...
- delphi 线程教学第三节:设计一个有生命力的工作线程
第三节:设计一个有生命力的工作线程 创建一个线程,用完即扔.相信很多初学者都曾这样使用过. 频繁创建释放线程,会浪费大量资源的,不科学. 1.如何让多线程能多次被复用? 关键是不让代码退出 ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- 第三百七十五节,Django+Xadmin打造上线标准的在线教育平台—创建课程机构app,在models.py文件生成3张表,城市表、课程机构表、讲师表
第三百七十五节,Django+Xadmin打造上线标准的在线教育平台—创建课程机构app,在models.py文件生成3张表,城市表.课程机构表.讲师表 创建名称为app_organization的课 ...
- 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- Java-NIO(三):直接缓冲区与非直接缓冲区
直接缓冲区与非直接缓冲区的概念: 1)非直接缓冲区:通过 static ByteBuffer allocate(int capacity) 创建的缓冲区,在JVM中内存中创建,在每次调用基础操作系统的 ...
- Effective Java 第三版——38. 使用接口模拟可扩展的枚举
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- MySQL 表空间传输
聊到MySQL数据迁移的话题,表空间传输时一个很实用的方法. 在MySQL 5.6 Oracle引入了一个可移动表空间的特征(复制的表空间到另一个服务器)和Percona Server采用部分备份,这 ...
- 深入理解Redux
前面的话 Redux是Flux思想的另一种实现方式.Flux是和React同时面世的.React用来替代jQuery,Flux用来替换Backbone.js等MVC框架.在MVC的世界里,React相 ...
- [LeetCode] Max Chunks To Make Sorted 可排序的最大块数
Given an array arr that is a permutation of [0, 1, ..., arr.length - 1], we split the array into som ...
- [LeetCode] Parse Lisp Expression 解析Lisp表达式
You are given a string expression representing a Lisp-like expression to return the integer value of ...
- 再深刻理解下web3.js中estimateGas如何计算智能合约消耗的gas量
我们可使用web3.js框架的estimateGas函数获得一个以太坊智能合约的Gas估计值 ,通过执行一个消息调用或交易,该消息调用或交易直接在节点的VM中执行,并未在区块链中确认,函数会返回估算使 ...
- 简陋的个人Vim使用命令
最近把Visual Studio 的编辑器改成了 Vim,感觉像发现了新世界,记录记录一些提高效率的Vim命令. 插入命令 i 在当前位置前插入 I 在当前行首插入 a 在当前位置后插入 A 在当前行 ...
- 【NOIP2009】Hankson 的趣味题
题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲解 ...
- Codeforces Round #460 E. Congruence Equation
Description 题面 \(n*a^n≡b (\mod P),1<=n<=x\) Solution 令 \(n=(P-1)*i+j\) \([(P-1)*i+j]*a^{[(P-1) ...