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)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- MySQLdb、 flask-MySQLdb 、MySQL-python 安装失败
今天在学习flask的时候,学习到数据库部分,连接mysql生成表,运行程序报错误:No module named MySQLdb 此时 需要安装 以下两个中任何一个 pip install flas ...
- 在GridControl表格控件中实现多层级主从表数据的展示
在一些应用场景中,我们需要实现多层级的数据表格显示,如常规的二级主从表数据展示,甚至也有多个层级展示的需求,那么我们如何通过DevExpress的GridControl控表格件实现这种业务需求呢?本篇 ...
- JavaScript是如何面向对象的
一.引言 在16年的10月份,在校内双选会找前端实习的时候,hr问了一个问题:JavaScript的面向对象理解吗?我张口就说"JavaScript是基于原型的!".然后就没什么好 ...
- hive-jdbc获取查询日志慢的问题发现与解决
1.问题描述: 数据平台的临时查询一直有一个问题,就是日志获取太慢了,每次都是和结果一块出来的,这就非常影响用户的体验,半天都没任何输出.另一个是Beeline客户端不一致,beeline客户端每次都 ...
- jquery的attr()方法
一.定义和用法 attr() 方法设置或返回被选元素的属性和值. 当该方法用于返回属性值,则返回第一个匹配元素的值. 当该方法用于设置属性值,则为匹配元素设置一个或多个属性/值对. 二.语法 返回属性 ...
- CodeForces 909E Coprocessor(无脑拓扑排序)
You are given a program you want to execute as a set of tasks organized in a dependency graph. The d ...
- [LeetCode] Reverse Words in a String III 翻转字符串中的单词之三
Given a string, you need to reverse the order of characters in each word within a sentence while sti ...
- [LeetCode] Teemo Attacking 提莫攻击
In LLP world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned ...
- JavaScript 和 TypeScript 中的 class
对于一个前端开发者来说,很少用到 class ,因为在 JavaScript 中更多的是 函数式 编程,抬手就是一个 function,几乎不见 class 或 new 的踪影.所以 设计模式 也是大 ...
- Efficient&Elegant:Java程序员入门Cpp
最近项目急需C++ 的知识结构,虽说我有过快速学习很多新语言的经验,但对于C++ 老特工我还需保持敬畏(内容太多),本文会从一个Java程序员的角度,制定高效学习路线快速入门C++ . Java是为了 ...