delphi 线程教学第六节:TList与泛型
unit uFooList;interfaceuses Generics.Collections;type TFooList <T>= class(TList<T>) private procedure FreeAllItems; protected procedure FreeItem(Item: T);virtual; // 子类中需要重载此过程。以确定到底如何释放 Item // 如果是 Item 是指针,就用 Dispose(Item); // 如果是 Item 是TObject ,就用 Item.free; public destructor Destroy;override; procedure ClearAllItems; procedure Lock; // 给本类设计一把锁。 procedure Unlock; end; // 定义加入到 List 的 Item 都由 List 来释放。 // 定义释放规则很重要!只有规则清楚了,才不会乱套。 // 通过这样简单的改造, TList 立马好用 N 倍。implementation{ TFooList<T> }procedure TFooList<T>.ClearAllItems;begin FreeAllItems; Clear;end;destructor TFooList<T>.Destroy;begin FreeAllItems; inherited;end;procedure TFooList<T>.FreeAllItems;var Item: T;begin for Item in self do FreeItem(Item);end;procedure TFooList<T>.FreeItem(Item: T);beginend;procedure TFooList<T>.Lock;begin System.TMonitor.Enter(self);end;procedure TFooList<T>.Unlock;begin System.TMonitor.Exit(self);end;end.unit uFrmMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uCountThread, uFooList;type TCountThreadList = Class(TFooList<TCountThread>) // 定义一个线程 List protected procedure FreeItem(Item: TCountThread); override; // 指定 Item 的释放方式。 end; TNumList = Class(TFooList<Integer>); // 定义一个 Integer List 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 } FNumList: TNumList; FCountThreadList: TCountThreadList; 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 LockCount; procedure UnlockCount; public { Public declarations } end;var FrmMain: TFrmMain;implementation{$R *.dfm}{ TFrmMain }{ TCountThreadList }procedure TCountThreadList.FreeItem(Item: TCountThread);begin inherited; Item.Free;end;procedure TFrmMain.btnWorkClick(Sender: TObject);var s: string; thd: TCountThread;begin btnWork.Enabled := false; FWorkedCount := 0; FBuffIndex := 0; FBuffMaxIndex := FNumList.Count - 1; s := '共' + IntToStr(FBuffMaxIndex + 1) + '个任务,已完成:' + IntToStr(FWorkedCount); lblInfo.Caption := s; for thd in FCountThreadList do begin thd.StartThread; end;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);var thd: TCountThread; i: Integer;begin FCountThreadList := TCountThreadList.Create; // 可以看出用了 List 之后,线程数量指定更加灵活。 // 多个线程在一个 List 中,这个 List 可以理解为线程池。 for i := 1 to 3 do begin thd := TCountThread.Create(false); FCountThreadList.Add(thd); thd.OnStatusMsg := self.OnThreadMsg; thd.OnGetNum := self.OnGetNum; thd.OnCounted := self.OnCounted; thd.ThreadName := '线程' + IntToStr(i); end; FNumList := TNumList.Create; // 构造一组数据用来测试 FNumList.Add(100); FNumList.Add(136); FNumList.Add(306); FNumList.Add(156); FNumList.Add(152); FNumList.Add(106); FNumList.Add(306); FNumList.Add(156); FNumList.Add(655); FNumList.Add(53); FNumList.Add(99); FNumList.Add(157);end;procedure TFrmMain.FormDestroy(Sender: TObject);begin FNumList.Free; FCountThreadList.Free;end;procedure TFrmMain.LockCount;begin System.TMonitor.Enter(btnWork);end;procedure TFrmMain.UnlockCount;begin System.TMonitor.Exit(btnWork);end;procedure TFrmMain.OnCounted(Sender: TCountThread);var s: string;begin LockCount; // 锁不同的对象,宜用不同的锁。 // 每把锁的功能要单一,锁的粒度要最小化。才能提高效率。 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 // 将多个线程访问 FNumList 排队。 FNumList.Lock; try if FBuffIndex > FBuffMaxIndex then begin result := false; end else begin Sender.Num := FNumList[FBuffIndex]; result := true; inc(FBuffIndex); end; finally FNumList.Unlock; end;end;procedure TFrmMain.OnThreadMsg(AMsg: string);begin TThread.Synchronize(nil, procedure begin DispMsg(AMsg); end);end;end.delphi 线程教学第六节:TList与泛型的更多相关文章
- delphi 线程教学第五节:多个线程同时执行相同的任务
第五节:多个线程同时执行相同的任务 1.锁 设,有一个房间 X ,X为全局变量,它有两个函数 X.Lock 与 X.UnLock; 有如下代码: X.Lock; 访问资源 P; ...
- delphi 线程教学第四节:多线程类的改进
第四节:多线程类的改进 1.需要改进的地方 a) 让线程类结束时不自动释放,以便符合 delphi 的用法.即 FreeOnTerminate:=false; b) 改造 Create 的参数 ...
- delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行
第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行 以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...
- delphi 线程教学第二节:在线程时空中操作界面(UI)
第二节:在线程时空中操作界面(UI) 1.为什么要用 TThread ? TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...
- delphi 线程教学第一节:初识多线程
第一节:初识多线程 1.为什么要学习多线程编程? 多线程(多个线程同时运行)编程,亦可称之为异步编程. 有了多线程,主界面才不会因为耗时代码而造成“假死“状态. 有了多线程,才能使多个任务同时 ...
- delphi 线程教学第一节:初识多线程(讲的比较浅显),还有三个例子
http://www.cnblogs.com/lackey/p/6297115.html 几个例子: http://www.cnblogs.com/lackey/p/5371544.html
- delphi 线程教学第三节:设计一个有生命力的工作线程
第三节:设计一个有生命力的工作线程 创建一个线程,用完即扔.相信很多初学者都曾这样使用过. 频繁创建释放线程,会浪费大量资源的,不科学. 1.如何让多线程能多次被复用? 关键是不让代码退出 ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环
http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...
随机推荐
- python开发:python基本数据类型
运算符 1.算数运算: 2.比较运算: 3.赋值运算: 4.逻辑运算: 5.成员运算: 基本数据类型 1.数字 int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31- ...
- linux系统下Apache日志分割(按天生成文件)
Apache日志按天显示,修改Apache http.conf文件,注释默认的日志文件,修改为下面2行 ErrorLog "| /usr/local/apache/bin/rotatelog ...
- Linux:日期用法,及格式定义
在shell脚本中经常会需要获取当前日期的地方,linux的系统时间在shell里是可以直接调用系统变量: 获取今天时期---`date +%Y%m%d` 或 `date +%F` 或 $(date ...
- [js]关于call()和apply()的理解
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向. 因为 JavaScript 的函数存在「定义时上下文」和 ...
- vue2.0 带头冲锋(打包时,小心萝卜坑)
距离上一期,时间间距可能有点长.谁让本人处于兴奋状态,生活已经不能自理. 哈哈哈,嗯,正经一下, 在已有的经验里总结一下那些容易抓狂的坑! 起因:npm run build 打包 本地运行,你以为可以 ...
- Spring MVC基础学习
SpringMVC是Spring框架的一个模块,无需通过中间层整合在一起.SpringMVC是一个基于MVC设计模式web框架,MVC-model-view-controller:MVC将服务器端分为 ...
- 创建类似于Oracle中SYS_GUID() 的方法
CREATE or REPLACE FUNCTION "sys_guid"()RETURNS "pg_catalog"."varchar" ...
- ubuntu14.4 分辨率偏低
最近出了 14.04 LTS,就想安装上玩一玩.还是用 easybcd 从 windows硬盘安装.装完之后,显示效果不好于是做了如下处理: 1. 按下windows键,搜索 "附加驱动&q ...
- POJ1222熄灯问题
千年老题,以前用枚举做,现在用高斯消元做 自由元直接做成0即可 #include<cstdio> #include<cstdlib> #include<algorithm ...
- UVA1658:Admiral
题意:给定一个有向带权图,求两条不相交(无公共点)的路径且路径权值之和最小,路径由1到v 题解:这题的关键就在于每个点只能走一遍,于是我们想到以边换点的思想,用边来代替点,怎么代替呢? 把i拆成i和i ...