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)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- Django ORM那些相关操作
一般操作 https://docs.djangoproject.com/en/1.11/ref/models/querysets/ 官网文档 常用的操作 <1> all() ...
- 理解Node.js安装及模块化
1.安装Node Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效. Node.j ...
- tensorflow让程序学习到函数y = ax + b中a和b的值
今天我们通过tensorflow来实现一个简单的小例子: 假如我定义一个一元一次函数y = 0.1x + 0.3,然后我在程序中定义两个变量 Weight 和 biases 怎么让我的这两个变量自己学 ...
- Python/模块与包之模块
Python/模块与包之模块 1.什么是模块? 模块就是py文件 2.为什么要用模块? 如果在解释器上进行编码,把解释器关闭之前写的文件就不存在了,如果使用模块的话就能永久保存在磁盘中. 3.如何使用 ...
- PHP 抓取网页内容的几个函数
<?php //获取所有内容url保存到文件 function get_index($save_file, $prefix="index_"){ $count = 68; $ ...
- javascript数组去重的3种方法
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! javascript数组去重 <!DOCTYPE html> <html> < ...
- Redis Cluster 4.0 on CentOS 6.9 搭建
集群简介 Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation). Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需 ...
- 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第一章
鉴于最近用 vuejs 框架开发项目,其中有很多涉及到 es6 语法不太理解所以便认真地读了一下这本书. 地址:http://es6.ruanyifeng.com/#README 第一章:let ...
- 发布你的程序包到Nuget
1.新建一个.NET Standard 的类库项目 2.选择项目熟悉,在 package 栏目下填写我们的nuget包信息 3.选择我们的项目,点击"Pack" 打包 主要注意的是 ...
- [LeetCode] Smallest Range 最小的范围
You have k lists of sorted integers in ascending order. Find the smallest range that includes at lea ...