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)
并发编程概述 前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...
随机推荐
- nginx配置反向代理详细教程(windows版)
内容属于原创,如果需要转载,还请注明地址:http://www.cnblogs.com/j-star/p/8785334.html Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(I ...
- python中文编码坑
打印list的时候unicode对象不会自动转为中文!
- Tensorflow计算模型 —— 计算图
转载自:http://blog.csdn.net/john_xyz/article/details/69053626 Tensorflow是一个通过计算图的形式来表述计算的编程系统,计算图也叫数据流图 ...
- python json.dumps 中的ensure_ascii 参数引起的中文编码问题
在使用json.dumps时要注意一个问题 >>> import json >>> print json.dumps('中国') "\u4e2d\u5 ...
- django 开发忘记密码通过邮箱找回功能
一.流程分析: 1.点击忘记密码====>forget.html页面,输入邮箱和验证码,发送验证链接网址的邮件====>发送成功,跳到send_success.html提示 2.到邮箱里找 ...
- ·c#之Thread实现暂停继续(转)
暂停与继续实现,可以使用Thread.Suspend和Thread.Resume而这两个方法,在VS2010里提示已经过时,不建议使用,在网上查阅了一些资料,发现有个事件通知的方法很好,事件通知的大致 ...
- 使用控制台调试WinForm窗体程序
.程序代码结构 .Win32DebuggerHelper.cs using System.Runtime.InteropServices; /* TODO:使用方法 Win32.AllocConsol ...
- 0323-DOM基础操作
dom操作 1.找到元素(标签对象) 标签名: document.getElementsByTagName()[]; //返回的是数组类型,需要有下标来找内容 属性: document.getElem ...
- Unity3D UGUI 自动调节大小
可添加以下组件 组件包含的两个枚举参数,可以自行设定适应方式. 例如一个Text UI元素,当文字过多的时候他不会自动增加高度而导致文字不能完全显示,这时候就可以挂载这个组件,如上图设置参数,就可以自 ...
- 【JDK1.8】JUC——LockSupport
一.前言 Basic thread blocking primitives for creating locks and other synchronization classes. 用于创建锁定和其 ...