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)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- NOPI实现导入导出泛型List,支持自定义列
概述 业务上需要自定义列的Excel的导入导出,在网上看了好多资料,很多都是有Bug而且都是支持Excel和DataTable的转换,所以自己总结了一下,应用.NET平台上的NPOI封装了支持自定义列 ...
- [机器学习实战]K-近邻算法
1. K-近邻算法概述(k-Nearest Neighbor,KNN) K-近邻算法采用测量不同的特征值之间的距离方法进行分类.该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近 ...
- CentOS7从U盘中拷贝文件
1. 要想从U盘中拷贝文件,必须要将U盘挂载到一个目录中,所以必须新建一个目录,一般建在/mnt下.我们执行:mkdir /mnt/usb来新建一个目录. 2. 查看U盘是否已经被识别.执行:df - ...
- Spark:导入数据到oracle
方案一: //overwrite JdbcDialect fitting for Oracle val OracleDialect = new JdbcDialect { override def c ...
- scrapy爬取中关村在线手机频道
# -*- coding: utf-8 -*- import scrapy from pyquery import PyQuery as pq from zolphone.items import Z ...
- pyspider爬取TripAdvisor
#!/usr/bin/env python # -*- encoding: utf-8 -*- # Created on 2017-06-11 10:10:53 # Project: london f ...
- DbContext(String)+SqlQuery一起使用
DbContext(String) 可以将给定字符串用作将连接到的数据库的名称或连接字符串来构造一个新的上下文实例. Database.SqlQuery 方法 (Type, String, Objec ...
- ionic新入坑-环境搭建+新建项目+打开低版本项目处理
是的.我又双叒叕入新坑了.想我大学的时候web-app刚火起来.还帮忙做了我们学校医务室系统的web-app页面部分呢.时间太紧最后也没出个完整的版本.那时候只是用H5简单做了web部分.是想着用ph ...
- CentOS安装node.js-8.11.1+替换淘宝NPM镜像
注:以下所有操作均在CentOS 6.8 x86_64位系统下完成. #准备工作# 由于node.js-8.11.1在源码编译安装的时候需要gcc 4.9.4或clang++ 3.4.2以上版本的支持 ...
- [LeetCode] Next Greater Element I 下一个较大的元素之一
You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of n ...