转载自:https://www.cnblogs.com/lackey/p/4782777.html
本例是把多个线程访问数据库的请求,全部阻塞到一个线程。
这是实际编程中常见的一种问题。
示例源码下载,所需支持单元均在源码中,且附详细说明。
TElegantThread 的父类是 TSimpleThread。
unit uElegantThread;
interface
uses
Classes, SysUtils, uSimpleThread, uSimpleList, uSyncObjs;
type
PSyncRec = ^TSyncRec;
TSyncRec = record
FMethod: TThreadMethod;
FProcedure: TThreadProcedure;
FSignal: TSuperEvent;
Queued: boolean;
DebugInfo: string;
end;
TSyncRecList = Class(TSimpleList<PSyncRec>)
protected
procedure FreeItem(Item: PSyncRec); override;
End;
TElegantThread = class(TSimpleThread)
private
FSyncRecList: TSyncRecList;
procedure LockList;
procedure UnlockList;
procedure Check;
procedure DoCheck;
public
// AAllowedActiveX 允许此线程访问 COM 如:IE ,
// 当然,获取 Ie 的 IHtmlDocument2 接口,也必须在此线程内执行
constructor Create(AAllowedActiveX: boolean = false);
destructor Destroy; override;
// ADebugInfo 是调用者用来查错用,一般可以写上过程名 如:'DoSomeThing';
procedure Queue(AMethod: TThreadMethod; ADebugInfo: string = ''); overload;
procedure Queue(AProcedure: TThreadProcedure; ADebugInfo: string = ''); overload;
procedure Synchronize(AMethod: TThreadMethod; ADebugInfo: string = ''); overload;
procedure Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string = ''); overload;
end;
implementation
{ TSyncRecList }
procedure TSyncRecList.FreeItem(Item: PSyncRec);
begin
inherited;
if Assigned(Item.FSignal) then
Item.FSignal.Free;
Dispose(Item);
end;
{ TElegantThread }
procedure TElegantThread.Check;
begin
ExeProcInThread(DoCheck);
end;
constructor TElegantThread.Create(AAllowedActiveX: boolean);
begin
inherited;
FSyncRecList := TSyncRecList.Create;
end;
destructor TElegantThread.Destroy;
begin
WaitThreadStop;
FSyncRecList.Free;
inherited;
end;
procedure TElegantThread.DoCheck;
var
p: PSyncRec;
sErrMsg: string;
begin
LockList;
try
p := FSyncRecList.PopFirst; // 每次从 List 取出一个过程来执行
finally
UnlockList;
end;
if Assigned(p) then
begin
try
if Assigned(p.FMethod) then
p.FMethod // 执行
else if Assigned(p.FProcedure) then
p.FProcedure(); // 执行
except
on E: Exception do // 错误处理
begin
sErrMsg := 'DebugInfo:' + p.DebugInfo + #13#10;
sErrMsg := sErrMsg + 'ErrMsg:' + E.Message;
DoOnDebugMsg(sErrMsg);
end;
end;
if not p.Queued then // 如果是阻塞,请设为有信号,调用者即可返回
begin
p.FSignal.SetEvent;
end;
Dispose(p);
Check; // 继续下一次 DoCheck,也就是本过程。
// 父类 TSimpleThread 已特殊处理,不会递归。
end;
end;
procedure TElegantThread.LockList;
begin
FSyncRecList.Lock;
end;
procedure TElegantThread.Queue(AMethod: TThreadMethod; ADebugInfo: string);
var
p: PSyncRec;
begin
// 此过程为排队执行
new(p);
p.FProcedure := nil;
p.FMethod := AMethod;
p.Queued := true;
LockList;
try
FSyncRecList.Add(p); // 把要执行的过程加入 List
Check; // 启动线程
finally
UnlockList;
end;
end;
procedure TElegantThread.Queue(AProcedure: TThreadProcedure; ADebugInfo: string);
var
p: PSyncRec;
begin
new(p);
p.FProcedure := AProcedure;
p.FMethod := nil;
p.Queued := true;
LockList;
try
FSyncRecList.Add(p);
Check;
finally
UnlockList;
end;
end;
procedure TElegantThread.Synchronize(AMethod: TThreadMethod; ADebugInfo: string);
var
p: PSyncRec;
o: TSuperEvent;
begin
// 此过程为阻塞执行,即调用者必须等到此过程被执行完成才能返回
new(p);
p.FProcedure := nil;
p.FMethod := AMethod;
p.Queued := false;
p.FSignal := TSuperEvent.Create; // 创建一个信号
p.FSignal.ResetEvent; // 清除信号
o := p.FSignal;
LockList;
try
FSyncRecList.Add(p);
Check;
finally
UnlockList;
end;
o.WaitFor; // 等待信号出现
o.Free;
end;
procedure TElegantThread.Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string);
var
p: PSyncRec;
o: TSuperEvent;
begin
new(p);
p.FProcedure := AProcedure;
p.FMethod := nil;
p.Queued := false;
p.FSignal := TSuperEvent.Create;
p.FSignal.ResetEvent;
o := p.FSignal;
LockList;
try
FSyncRecList.Add(p);
Check;
finally
UnlockList;
end;
o.WaitFor;
o.Free;
end;
procedure TElegantThread.UnlockList;
begin
FSyncRecList.Unlock;
end;
end.
uElegantThread.pas
unit uElegantThread;
interface
uses Classes, SysUtils, uSimpleThread, uSimpleList, uSyncObjs;
type
PSyncRec = ^TSyncRec;
TSyncRec = record FMethod: TThreadMethod; FProcedure: TThreadProcedure; FSignal: TSuperEvent; Queued: boolean; DebugInfo: string; end;
TSyncRecList = Class(TSimpleList<PSyncRec>) protected procedure FreeItem(Item: PSyncRec); override; End;
TElegantThread = class(TSimpleThread) private FSyncRecList: TSyncRecList;
procedure LockList; procedure UnlockList;
procedure Check; procedure DoCheck;
public
// AAllowedActiveX 允许此线程访问 COM 如:IE , // 当然,获取 Ie 的 IHtmlDocument2 接口,也必须在此线程内执行 constructor Create(AAllowedActiveX: boolean = false); destructor Destroy; override;
// ADebugInfo 是调用者用来查错用,一般可以写上过程名 如:'DoSomeThing'; procedure Queue(AMethod: TThreadMethod; ADebugInfo: string = ''); overload; procedure Queue(AProcedure: TThreadProcedure; ADebugInfo: string = ''); overload;
procedure Synchronize(AMethod: TThreadMethod; ADebugInfo: string = ''); overload; procedure Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string = ''); overload;
end;
implementation
{ TSyncRecList }
procedure TSyncRecList.FreeItem(Item: PSyncRec);begin inherited; if Assigned(Item.FSignal) then Item.FSignal.Free; Dispose(Item);end;
{ TElegantThread }
procedure TElegantThread.Check;begin ExeProcInThread(DoCheck);end;
constructor TElegantThread.Create(AAllowedActiveX: boolean);begin inherited; FSyncRecList := TSyncRecList.Create;end;
destructor TElegantThread.Destroy;begin WaitThreadStop; FSyncRecList.Free; inherited;end;
procedure TElegantThread.DoCheck;var p: PSyncRec; sErrMsg: string;begin
LockList; try p := FSyncRecList.PopFirst; // 每次从 List 取出一个过程来执行 finally UnlockList; end;
if Assigned(p) then begin
try
if Assigned(p.FMethod) then p.FMethod // 执行 else if Assigned(p.FProcedure) then p.FProcedure(); // 执行
except on E: Exception do // 错误处理 begin sErrMsg := 'DebugInfo:' + p.DebugInfo + #13#10; sErrMsg := sErrMsg + 'ErrMsg:' + E.Message; DoOnDebugMsg(sErrMsg); end; end;
if not p.Queued then // 如果是阻塞,请设为有信号,调用者即可返回 begin p.FSignal.SetEvent; end;
Dispose(p); Check; // 继续下一次 DoCheck,也就是本过程。 // 父类 TSimpleThread 已特殊处理,不会递归。
end;
end;
procedure TElegantThread.LockList;begin FSyncRecList.Lock;end;
procedure TElegantThread.Queue(AMethod: TThreadMethod; ADebugInfo: string);var p: PSyncRec;begin // 此过程为排队执行
new(p); p.FProcedure := nil; p.FMethod := AMethod; p.Queued := true;
LockList; try FSyncRecList.Add(p); // 把要执行的过程加入 List Check; // 启动线程 finally UnlockList; end;
end;
procedure TElegantThread.Queue(AProcedure: TThreadProcedure; ADebugInfo: string);var p: PSyncRec;begin new(p); p.FProcedure := AProcedure; p.FMethod := nil; p.Queued := true; LockList; try FSyncRecList.Add(p); Check; finally UnlockList; end;end;
procedure TElegantThread.Synchronize(AMethod: TThreadMethod; ADebugInfo: string);var p: PSyncRec; o: TSuperEvent;begin
// 此过程为阻塞执行,即调用者必须等到此过程被执行完成才能返回
new(p);
p.FProcedure := nil; p.FMethod := AMethod; p.Queued := false; p.FSignal := TSuperEvent.Create; // 创建一个信号 p.FSignal.ResetEvent; // 清除信号 o := p.FSignal;
LockList; try FSyncRecList.Add(p); Check; finally UnlockList; end;
o.WaitFor; // 等待信号出现 o.Free;
end;
procedure TElegantThread.Synchronize(AProcedure: TThreadProcedure; ADebugInfo: string);var p: PSyncRec; o: TSuperEvent;begin new(p);
p.FProcedure := AProcedure; p.FMethod := nil; p.Queued := false; p.FSignal := TSuperEvent.Create; p.FSignal.ResetEvent; o := p.FSignal;
LockList; try FSyncRecList.Add(p); Check; finally UnlockList; end;
o.WaitFor; o.Free;
end;
procedure TElegantThread.UnlockList;begin FSyncRecList.Unlock;end;
end.
uElegantThread.pas