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类使 ...
随机推荐
- mysql自带的example测试数据库导入Centos6.5
1.下载数据库 下载地址: [test数据库] (https://github.com/datacharmer/test_db) 不出意外的话,下载下来是个unzip文件. 2.上传到数据库服务器 r ...
- 基于UDP协议的控制台聊天程序(c++版)
本博客由Rcchio原创,转载请告知作者 ------------------------------------------------------------------------------- ...
- UVA850【简单模拟】
题目:解密句子.有一些被加密的句子已知一条模板翻译,判断是否可以解密,可以的话将所有句子解密. #include <stdio.h> #include<iostream> #i ...
- POJ-2485 Highways---最小生成树中最大边
题目链接: https://vjudge.net/problem/POJ-2485 题目大意: 求最小生成树中的最大边 思路: 是稠密图,用prim更好,但是规模不大,kruskal也可以过 #inc ...
- 正则-匹配IP地址
>>> re.search(r'[aeiouAEIOU]','I love FishC.com!') 中括号里面的任意一个字符匹配成功就会返回数值 <_sre.SRE_Matc ...
- Mybatis JPA 插件简介(v2.1.0)
相比之前的版本(v1.1.0),此版本(v2.1.0)做了较大的改动. 项目地址: github https://github.com/cnsvili/mybatis-jpa gitee https: ...
- ·c#之Thread实现暂停继续(转)
暂停与继续实现,可以使用Thread.Suspend和Thread.Resume而这两个方法,在VS2010里提示已经过时,不建议使用,在网上查阅了一些资料,发现有个事件通知的方法很好,事件通知的大致 ...
- [LeetCode] Candy Crush 糖果消消乐
This question is about implementing a basic elimination algorithm for Candy Crush. Given a 2D intege ...
- Java基础知识回顾之四 ----- 集合List、Map和Set
前言 在上一篇中回顾了Java的三大特性:封装.继承和多态.本篇则来介绍下集合. 集合介绍 我们在进行Java程序开发的时候,除了最常用的基础数据类型和String对象外,也经常会用到集合相关类. 集 ...
- cd
从当前目录切换到目标目录 cd [目标目录] 切换到用户主目录 cd cd~ 切换到根目录 cd / 切换到上级目录 cd .. cd ../ cd ..// 切换到上级目录的父目录 ...