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类使 ...
随机推荐
- requests+正则表达式提取猫眼电影top100
#requests+正则表达式提取猫眼电影top100 import requests import re import json from requests.exceptions import Re ...
- AngularJS 全局scope与指令 scope通信
在项目开发时,全局scope 和 directive本地scope使用范围不够清晰,全局scope与directive本地scope通信掌握的不够透彻,这里对全局scope 和 directive本地 ...
- string[] 清理重复+反转显示
string[] listUrl = String.Join(",", list.Replace("\r\n", ",").Split(', ...
- JS随机数不重复
方法一 思路:首先创建一个1到3000的数组,每次取一个数,然后去除数组中取出的这个数, 这样就可以实现永不重复. var count=3000; var originalArray=new Arra ...
- codeforces 842C Ilya And The Tree
Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very ...
- [HNOI2013]比赛
题目描述 沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛.此次联 赛共N支球队参加,比赛规则如下: (1) 每两支球队之间踢一场比赛. (2) 若平局,两支球队各得1分. (3) ...
- 【BZOJ1026】【SCOI2009】windy数
Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? In ...
- bzoj 3261最大异或和
Description 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1. 2.Qlrx:询问操作,你需要 ...
- 【集训第三天·疯狂训练】哦,顺带学习了manacher
虽然说是疯狂训练吧,但是也没写多少题,就把伸展树的操作熟悉了一下,ac了5个题目. 一整天没啥可吐槽的,除了昨天在机房打游戏的某位朋友翻车后和教练谈了谈心2333 说题吧.. 1.BZOJ1208 H ...
- 面试题2:实现Singleton模式
题目:设计一个类,我们只能生成该类的一个实例.