[转载]Delphi线程池(Delphi2009以上版本适用)
在网上查找Delphi线程池,结果发现寥寥无几。看了半天源代码,弄得一头雾水,觉得不容易理解和使用,于是自己想写一个线程池。什么样的线程池更好呢?我觉得使用起来要可靠,并且一定要简单,这样才是更好的。我写的线程池就是这样一个标准,使用非常简单,只传入自己要执行的方法就可以了,其实大家最后就是关注自己要操作的方法,其余的交给线程池。全部源代码如下:
//单元:ThreadPoolUint
//说明:线程池
//
//Rev. 开发日期
开发者 EMail
//Ver.1.0.0 2011/05/05
孙玉良
sunylat@gmail.com
Vcl.Forms;
// 要执行任务的记录
TaskRec = record
isSynchronize: Boolean;
// 是否需要同步执行
TaskProc:
TThreadProcedure; // 要执行任务的方法
end;
// 执行具体任务线程
TExecuteThread = class(TThread)
private
FProc: TThreadProcedure;
// 要执行的任务方法
FIsCanTask: Boolean; //
是否可以执行任务
FIsSynchronize: Boolean;
// 是否用同步执行
procedure showThreadID;
// 显示线程编号(测试使用)
protected
procedure Execute;
override;
public
constructor
Create(CreateSuspended: Boolean); overload;
public
procedure
StartTask(task: TaskRec); // 执行任务
end;
// 线程池类(单例模式的类,做为全局使用的类)
ThreadPool = class(TObject)
private
FMREWSync: TMREWSync; //
共享读独占写变量
FTaskQueue:
TQueue<TaskRec>; // 要执行任务队列
FTaskThreadList:
TList<TExecuteThread>; //
执行任务线程List
FThreadMin: Integer; //
最小线程数量
FThreadMax: Integer; //
最大线程数量
// 共享读独占写方法
procedure BeginWrite; //
独占写开始
procedure EndWrite; //
独占写结束
procedure BeginRead; //
共享读开始
procedure EndRead; //
共享读结束
procedure
StopTaskAndFree; // 停止执行任务并释放相关资源
protected
constructor
CreateInstance(const minCount: Integer = 5;
const
maxCount: Integer = 20);
class function
AccessInstance(Request: Integer; const minCount: Integer = 5;
const
maxCount: Integer = 20): ThreadPool;
public
constructor Create; //
构造函数
destructor destroy;
override; // 析构函数
class function
Instance(const minCount: Integer = 5;
const
maxCount: Integer = 20): ThreadPool; // 实例化函数,客户端调用此函数
class procedure
ReleaseInstance; // 释放资源函数,客户端调用此函数
procedure AddTask(task:
TaskRec); // 添加要执行的任务
function IsHaveTask:
Boolean; // 是否有要执行的任务
procedure ExecuteTask;
// 执行任务
function
DoNextTask(executeThread: TExecuteThread): Boolean; // 执行下一任务
function
IsSuspend(executeThread: TExecuteThread): Boolean; // 挂起线程
function GetPoolState:
string; // 得到线程池状态
end;
inherited Create;
raise
Exception.CreateFmt('Utils类只能通过Instance方法来创建和访问%s的实例!',
[ClassName]);
const maxCount: Integer = 20);
i: Integer;
inherited Create;
// 需要在构造函数中初始化数据全部在此初始化
// 创建多线程共享读独占写变量
Self.FMREWSync := TMREWSync.Create;
Self.FTaskQueue :=
TQueue<TaskRec>.Create; //
实例化要执行的任务队列
Self.FTaskThreadList :=
TList<TExecuteThread>.Create; //
实例化执行任务线程List
Self.FThreadMin := minCount; //
最小线程数量
Self.FThreadMax := maxCount; //
最大线程数量
// 创建最小数量的线程
for i := 0 to minCount - 1 do
begin
// 把线程添加到线程List中
Self.FTaskThreadList.Add(TExecuteThread.Create(true));
end;
// 需要析构前完成操作全部在此完成
Self.StopTaskAndFree; // 释放线程池资源
// 释放多线程共享读独占写变量
Self.FMREWSync.Free;
if AccessInstance(0) = Self then
begin
AccessInstance(2);
end;
inherited destroy;
const minCount: Integer = 5; const
maxCount: Integer = 20): ThreadPool;
FInstance: ThreadPool = nil;
{
AccessInstance(0):不作任何处理,供释放实例对象时使用。
AccessInstance(1):存在该实例时直接使用,不存在时则创建该实例。
AccessInstance(2):返回一个空指针,用于重新设置实例。
}
case Request of
0:
;
1:
if
not Assigned(FInstance) then
begin
FInstance := CreateInstance(minCount,
maxCount);
end;
2:
FInstance := nil;
else
raise
Exception.CreateFmt(' %d 是AccessInstance()中的非法调用参数。',
[Request]);
end;
Result := FInstance;
const maxCount: Integer = 20):
ThreadPool;
// 返回实例
Result := AccessInstance(1, minCount,
maxCount);
AccessInstance(0).Free;
whileCount: Integer; // while循环计数变量
taskThread: TExecuteThread;
// 1,释放线程List
try
Self.BeginWrite;
whileCount := 0; //
while循环计数默认值为0
while whileCount
< Self.FTaskThreadList.count do
begin
taskThread := Self.FTaskThreadList.Items[whileCount]; //
得到工作线程
Self.FTaskThreadList.Delete(whileCount); // 从线程列表中删除线程
taskThread.Terminate; // 终止线程
Inc(whileCount); // while循环计数递增
end;
finally
Self.EndWrite;
Self.FTaskThreadList.Free; // 释放线程List
end;
// 2,释放任务队列
Self.FTaskQueue.Clear;
Self.FTaskQueue.Free;
Self.FMREWSync.BeginWrite;
Self.FMREWSync.EndWrite;
Self.FMREWSync.BeginRead;
Self.FMREWSync.EndRead;
// 添加任务到线程池中
try
Self.BeginWrite;
Self.FTaskQueue.Enqueue(task); // 把要执行任务加入任务队列
finally
Self.EndWrite;
end;
temp: Boolean;
temp := false;
try
Self.BeginRead;
// 判断有要执行的任务
if Self.FTaskQueue.count
> 0 then
begin
temp
:= true;
end;
finally
Self.EndRead;
end;
Result := temp;
whileCount: Integer; // while循环计数变量
isCanCreateThread: Boolean; //
是否可以创建新线程
curThread: TExecuteThread;
// 在主界面memo中显示信息
Form1.log('开始执行任务'); // 测试使用,正式使用删除
if Self.IsHaveTask then
begin
//
1,判断是否有可以执行任务线程,如果有直接让线程执行
try
Self.BeginRead;
whileCount := 0; // while循环计数变量默认值为0
while
whileCount < Self.FTaskThreadList.count do
begin
// 判断当前线程为挂起状态
if
Self.FTaskThreadList.Items[whileCount].Suspended then
begin
Self.FTaskThreadList.Items[whileCount].Resume; // 唤醒挂起线程
end;
Inc(whileCount); // while循环计数递增
end;
finally
Self.EndRead;
//
判断有要执行的任务
if
Self.IsHaveTask then
begin
// 是否可以创建新线程默认值为false
isCanCreateThread := false;
try
Self.BeginRead;
// 判断当前线程总数小于最大线程数量
if Self.FTaskThreadList.count
< Self.FThreadMax then
begin
isCanCreateThread := true;
///
/是否可以创建新线程为true
end;
finally
Self.EndRead;
// 判断可以创建新线程
if isCanCreateThread
then
begin
while
Self.FTaskThreadList.count < Self.FThreadMax
do
begin
// 创建新线程
curThread := TExecuteThread.Create(true);
try
Self.BeginWrite;
// 把新线程加入线程List
Self.FTaskThreadList.Add(curThread);
finally
Self.EndWrite;
end;
curThread.Resume;
end;
end;
end;
end;
end;
end;
isDoNextTask: Boolean; // 是否执行下一任务
nextTaskRec: TaskRec; // 下一任务结构
temp: Boolean;
temp := false; // 返回布尔值默认值为false
try
isDoNextTask := false;
// 是否执行下一任务默认值为false
Self.BeginWrite;
// 判断有要执行的任务
if Self.FTaskQueue.count
> 0 then
begin
nextTaskRec := Self.FTaskQueue.Dequeue;
isDoNextTask := true; // 是否执行任务为true
temp
:= true; // 返回布尔值为true
end;
finally
Self.EndWrite;
// 判断执行下一任务
if isDoNextTask
then
begin
executeThread.StartTask(nextTaskRec); // 执行任务
end;
end;
Result := temp;
temp: Boolean;
isRemove: Boolean;
temp := false;
try
Self.BeginRead;
isRemove := false; //
是否从线程List中删除当前线程默认值为false
//
判断线程数量是否大于最小线程数量
if
Self.FTaskThreadList.count > Self.FThreadMin
then
begin
isRemove := true; // 是否从线程List中删除当前线程为true
end
else
begin
temp
:= true; // 是否挂起为true
end;
finally
Self.EndRead;
//
判断从线程List中删除当前线程
if isRemove then
begin
try
Self.BeginWrite;
// 从线程List中删除当前线程
Self.FTaskThreadList.Remove(executeThread);
finally
Self.EndWrite;
end;
end;
end;
Result := temp;
temp: string; // 返回值变量
i: Integer; // 循环计数变量
curThread: TExecuteThread;
temp := '线程状态:' + #13#10;;
temp := temp + '最小线程数:' +
inttostr(Self.FThreadMin) + #13#10;
temp := temp + '最大线程数:' +
inttostr(Self.FThreadMax) + #13#10;
try
Self.BeginRead;
temp := temp + '线程总数:' +
inttostr(Self.FTaskThreadList.count) + #13#10;
temp := temp +
#13#10;
temp := temp + '线程详细信息:'
+ #13#10;
temp := temp +
#13#10;
for i := 0 to
Self.FTaskThreadList.count - 1 do
begin
curThread := Self.FTaskThreadList.Items[i];
temp
:= temp + '线程-' + inttostr(i + 1) + #13#10;
temp
:= temp + '线程编号:' + inttostr(curThread.ThreadID) + #13#10;
//
是否挂起
if
curThread.Suspended then
begin
temp := temp + '是否挂起: True' + #13#10;
end
else
begin
temp := temp + '是否挂起: False' + #13#10;
end;
//
是否可以执行任务
if
curThread.FIsCanTask then
begin
temp := temp + '是否可以执行: True' + #13#10;
end
else
begin
temp := temp + '是否可以执行: False' + #13#10;
end;
//
是否同步执行任务
if
curThread.FIsSynchronize then
begin
temp := temp + '是否同步执行: True' + #13#10;
end
else
begin
temp := temp + '是否同步执行: False' + #13#10;
end;
temp
:= temp + #13#10;
end;
finally
Self.EndRead;
end;
Result := Trim(temp);
inherited Create(CreateSuspended);
FreeOnTerminate := true;
Self.FIsCanTask := false; //
是否可以执行任务默认值为false
Self.FIsSynchronize := false; //
是否同步执行默认值为false
with Form1 do
begin
Memo1.Lines.Add('停止执行任务线程编号:' + inttostr(Self.ThreadID))
end;
while not Terminated do
begin
if Terminated then
begin
Break;
end;
// 判断可以执行任务
if Self.FIsCanTask
then
begin
Self.FProc(); // 执行任务
end;
// 判断不执行任务
if
ThreadPool.Instance.DoNextTask(Self) = false then
begin
//
显示执行任务线程编号
Synchronize(Self.showThreadID); // 测试使用,正式使用删除
//
判断挂起当前线程
if
ThreadPool.Instance.IsSuspend(Self) then
begin
Self.Suspend; // 挂起
end
else
// 不挂起则终止当前线程
begin
Self.Terminate; // 终止
end;
end;
// 使界面有反应
Application.ProcessMessages;
end;
Self.FProc := task.TaskProc; //
设置要执行的任务
Self.FIsSynchronize := task.isSynchronize;
// 设置是否同步执行
Self.FIsCanTask := true; //
设置是否可以执行任务为true
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
System.DateUtils,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Button7: TButton;
teskCountEdt:
TEdit;
Button8: TButton;
useTimeLab:
TLabel;
Label1: TLabel;
procedure
Button1Click(Sender: TObject);
procedure
Button7Click(Sender: TObject);
procedure
Button3Click(Sender: TObject);
procedure
FormDestroy(Sender: TObject);
procedure
Button2Click(Sender: TObject);
procedure
Button8Click(Sender: TObject);
private
{ Private declarations
}
public
{ Public declarations
}
procedure log(lgoInfo:
string); // log方法
end;
Form1: TForm1;
repeatCount: Integer = 0;
startTime: TDateTime; // 开始时间
useTime: Double; // 用时
count: Integer;
// with Form1 do
// begin
//
// inc(repeatCount);
//
//
Memo1.Lines.Add(FormatDateTime('yyyy-mm-dd hh:mm:ss', Now) +
// ' repeat count-' +
IntToStr(repeatCount));
//
// // count := 50000;
// //
// // while count > 0
do
// // begin
// // Dec(count);
// // end;
//
// end;
count := 0;
while count < 100000
do
begin
inc(count);
end;
ThreadPool.Instance(5, 20);
self.log('线程池创建了');
task: TaskRec;
I: Integer;
timeStr: string;
posInt: Integer;
startTime := Now;
useTimeLab.Caption := '0';
// 演示代码开始-----------------------
// 循环添加要执行的任务
// 1,添加要执行任务
for I := 0 to StrToInt(teskCountEdt.Text) -
1 do
begin
// 执行任务记录
task.isSynchronize :=
false;
task.TaskProc :=
TaskFun;
// 添加要执行的任务
ThreadPool.Instance.AddTask(task);
end;
// 2,让线程池执行任务
ThreadPool.Instance.ExecuteTask;
// 演示代码结束-----------------------
useTime := MilliSecondSpan(startTime,
Now);
timeStr := FloatToStr(useTime);
posInt := Pos('.', timeStr);
Delete(timeStr, posInt, Length(timeStr) -
(posInt - 1));
useTimeLab.Caption := '共用时: ' + timeStr + '
毫秒';
self.log(ThreadPool.Instance.GetPoolState);
// 显示线程池状态
ThreadPool.ReleaseInstance;
self.log('线程池释放了');
Memo1.Clear;
repeatCount := 0;
useTimeLab.Caption := '0';
ThreadPool.ReleaseInstance;
Memo1.Lines.Add('');
Memo1.Lines.Add(FormatDateTime('yyyy-mm-dd
hh:mm:ss', Now) + ' ' +
trim(lgoInfo))
//1,定义一个要执行任务的结构
task.isSynchronize :=
false;//是否同步执行
task.TaskProc :=
TaskFun;//要执行任务方法
// 2,向线程池添加要执行的任务
ThreadPool.Instance.AddTask(task);
// 3,让线程池执行任务
ThreadPool.Instance.ExecuteTask;
{
}
unit ThreadPoolUint;
// 定义多线程共享读独占写条件编译
{$DEFINE MULTI_THREAD_WRITE-READ}
interface
uses System.Classes, System.SysUtils, System.Math,
System.Generics.Collections,
type
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
implementation
{$J+}
{ MainUnit是为了测试引入的窗体单元,实际使用时候删除此单元和相关代码 }
uses MainUnit;
//
-----------------------------------------------------------------------------
// 构造函数
constructor ThreadPool.Create;
begin
end;
// 创建实例方法
constructor ThreadPool.CreateInstance(const minCount: Integer
= 5;
var
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
// 析构函数
destructor ThreadPool.destroy;
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
class function ThreadPool.AccessInstance(Request:
Integer;
const
begin
end;
// 得到类实例
class function ThreadPool.Instance(const minCount: Integer =
5;
begin
end;
// 释放资源
class procedure ThreadPool.ReleaseInstance;
begin
end;
{ ---- 类函数结束 ---- }
procedure ThreadPool.StopTaskAndFree;
var
begin
end;
// 独占写开始
procedure ThreadPool.BeginWrite;
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
// 独占写结束
procedure ThreadPool.EndWrite;
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
// 共享读开始
procedure ThreadPool.BeginRead;
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
// 共享读结束
procedure ThreadPool.EndRead;
begin
{$IFDEF MULTI_THREAD_WRITE-READ}
{$ENDIF}
end;
// 给线程池添加任务
procedure ThreadPool.AddTask(task: TaskRec);
begin
end;
// 是否有要执行的任务
function ThreadPool.IsHaveTask: Boolean;
var
begin
end;
// 执行任务
procedure ThreadPool.ExecuteTask;
var
begin
end;
// 执行下一任务
function ThreadPool.DoNextTask(executeThread: TExecuteThread):
Boolean;
var
begin
end;
// 判断线程是否需要挂起
function ThreadPool.IsSuspend(executeThread: TExecuteThread):
Boolean;
var
begin
end;
// 得到线程池状态
function ThreadPool.GetPoolState: string;
var
begin
end;
//
-----------------------------------------------------------------------------
// 执行任务线程构造函数
constructor TExecuteThread.Create(CreateSuspended:
Boolean);
begin
end;
// 显示线程编号(测试使用)
procedure TExecuteThread.showThreadID;
begin
end;
// 执行任务线程的主方法
procedure TExecuteThread.Execute;
begin
end;
// 设置要执行的任务
procedure TExecuteThread.StartTask(task: TaskRec);
begin
end;
end.
演示例子代码:
unit MainUnit;
interface
uses
type
var
implementation
{$R *.dfm}
uses ThreadPoolUint;
procedure TaskFun;
var
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
end;
procedure TForm1.Button2Click(Sender: TObject);
var
begin
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
end;
procedure TForm1.Button7Click(Sender: TObject);
begin
end;
procedure TForm1.Button8Click(Sender: TObject);
begin
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
end;
procedure TForm1.log(lgoInfo: string);
begin
end;
end.
调用线程池的代码是:
如果您有任何建议,请联系:sunylat@gmail.com QQ:14667479