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;interfaceuses 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)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- Kafka Cached zkVersion [62] not equal to that in zookeeper, skip updating ISR (kafka.cluster.Partition) 问题分析
我司业务Kafka集群是3节点(broker分别为10,20,30),每个Topic 3 Partition,3 Repilication的配置,早上起床突然发现所有Topic的Broker节点都变为 ...
- spark分区数,task数目,core数,worker节点个数,excutor数量梳理
作者:王燚光链接:https://www.zhihu.com/question/33270495/answer/93424104来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- MongoDB 更新文档
MongoDB 使用 update() 和 save() 方法来更新集合中的文档.接下来让我们详细来看下两个函数的应用及其区别. update() 方法 update() 方法用于更新已存在的文档.语 ...
- 列表&元组的内置方法
标红为元组可以使用
- jade 详解
简介 jade 是HTMl模板引擎,用javascript编写,可以在Node.js中使用.本文主要介绍原生node操作jade文件的方法. 安装 npm install jade 方法(API) ...
- [LeetCode] Stickers to Spell Word 贴片拼单词
We are given N different types of stickers. Each sticker has a lowercase English word on it. You wou ...
- 接口自动化测试:python+json+requests+数据驱动
接口测试是单元测试的一个子集,但又不等同于单元测试.从测试的角度来看,接口测试的价值在于其测试投入比单元测试少,而且技术难度也比单元测试小.一般来说,接口测试的粒度要比单元测试更粗,它主要是基于子系统 ...
- 视觉slam学习之路(一)看高翔十四讲所遇到的问题
目前实验室做机器人,主要分三个方向,定位导航,建图,图像识别,之前做的也是做了下Qt上位机,后面又弄红外识别,因为这学期上课也没怎么花时间在项目,然后导师让我们确定一个方向来,便于以后发论文什么. ...
- [SDOI 2008]Cave 洞穴勘测
Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...
- [CQOI2013]棋盘游戏
Description 一个n*n(n>=2)棋盘上有黑白棋子各一枚.游戏者A和B轮流移动棋子,A先走. A的移动规则:只能移动白棋子.可以往上下左右四个方向之一移动一格. B的移动规则:只能移 ...