Delphi对象池MyObjectPool.pas

对象池一般在服务端使用,所以稳定性是第一的。

欢迎提意见

unit uMyObjectPool;

interface

uses
  SyncObjs, Classes, Windows, SysUtils;

type
  TObjectBlock = record
  private
    FObject:TObject;
    FUsing:Boolean;
    FBorrowTime:Cardinal;   //借出时间
    FRelaseTime:Cardinal;   //归还时间
  end;

  PObjectBlock = ^TObjectBlock;

  TMyObjectPool = class(TObject)
  private
    FObjectClass:TClass;

    FLocker: TCriticalSection;

    //全部归还信号
    FReleaseSingle: THandle;

    //有可用的对象信号灯
    FUsableSingle: THandle;

    FMaxNum: Integer;

    /// <summary>
    ///   正在使用的对象列表
    /// </summary>
    FBusyList:TList;

    /// <summary>
    ///   可以使用的对象列表
    /// </summary>
    FUsableList:TList;

    FName: String;
    FTimeOut: Integer;


    procedure makeSingle;
    function GetCount: Integer;
    procedure lock;
    procedure unLock;
  protected
    /// <summary>
    ///   清理空闲的对象
    /// </summary>
    procedure clear;

    /// <summary>
    ///  创建一个对象
    /// </summary>
    function createObject: TObject; virtual;
  public
    constructor Create(pvObjectClass: TClass = nil);
    destructor Destroy; override;

    /// <summary>
    ///  重置对象池
    /// </summary>
    procedure resetPool;

    /// <summary>
    ///  借用一个对象
    /// </summary>
    function borrowObject: TObject;


    /// <summary>
    ///   归还一个对象
    /// </summary>
    procedure releaseObject(pvObject:TObject);

    /// <summary>
    ///  获取正在使用的个数
    /// </summary>
    function getBusyCount:Integer;



    //等待全部还回
    function waitForReleaseSingle: Boolean;

    /// <summary>
    ///   等待全部归还信号灯
    /// </summary>
    procedure checkWaitForUsableSingle;

    /// <summary>
    ///  当前总的个数
    /// </summary>
    property Count: Integer read GetCount;

    /// <summary>
    ///  最大对象个数
    /// </summary>
    property MaxNum: Integer read FMaxNum write FMaxNum;



    /// <summary>
    ///  对象池名称
    /// </summary>
    property Name: String read FName write FName;

    /// <summary>
    ///   等待超时信号灯
    ///   单位毫秒
    /// </summary>
    property TimeOut: Integer read FTimeOut write FTimeOut;
  end;

implementation

procedure TMyObjectPool.clear;
var
  lvObj:PObjectBlock;
begin
  lock;
  try
    while FUsableList.Count > 0 do
    begin
      lvObj := PObjectBlock(FUsableList[FUsableList.Count-1]);
      lvObj.FObject.Free;
      FreeMem(lvObj, SizeOf(TObjectBlock));
      FUsableList.Delete(FUsableList.Count-1);
    end; 
  finally
    unLock;
  end;
end;

constructor TMyObjectPool.Create(pvObjectClass: TClass = nil);
begin
  inherited Create;
  FObjectClass := pvObjectClass;
  
  FLocker := TCriticalSection.Create();
  FBusyList := TList.Create;
  FUsableList := TList.Create;

  //默认可以使用5个
  FMaxNum := 5;

  //等待超时信号灯 5 秒
  FTimeOut := 5 * 1000;

  //
  FUsableSingle := CreateEvent(nil, True, True, nil);

  //创建信号灯,手动控制
  FReleaseSingle := CreateEvent(nil, True, True, nil);

  makeSingle;
end;

function TMyObjectPool.createObject: TObject;
begin
  Result := nil;
  if FObjectClass <> nil then
  begin
    Result := FObjectClass.Create;
  end;      
end;

destructor TMyObjectPool.Destroy;
begin
  waitForReleaseSingle;  
  clear;
  FLocker.Free;
  FBusyList.Free;
  FUsableList.Free;

  CloseHandle(FUsableSingle);
  CloseHandle(FReleaseSingle);
  inherited Destroy;
end;

function TMyObjectPool.getBusyCount: Integer;
begin
  Result := FBusyList.Count;
end;

{ TMyObjectPool }

procedure TMyObjectPool.releaseObject(pvObject:TObject);
var
  i:Integer;
  lvObj:PObjectBlock;
begin
  lock;
  try
    for i := 0 to FBusyList.Count - 1 do
    begin
      lvObj := PObjectBlock(FBusyList[i]);
      if lvObj.FObject = pvObject then
      begin
        FUsableList.Add(lvObj);
        lvObj.FRelaseTime := GetTickCount;
        FBusyList.Delete(i);
        Break;
      end;
    end;             

    makeSingle;
  finally
    unLock;
  end;
end;

procedure TMyObjectPool.resetPool;
begin
  waitForReleaseSingle;

  clear;
end;

procedure TMyObjectPool.unLock;
begin
  FLocker.Leave;
end;

function TMyObjectPool.borrowObject: TObject;
var
  i:Integer;
  lvObj:PObjectBlock;
  lvObject:TObject;
begin
  Result := nil;


  while True do
  begin
    //是否有可用的对象
    checkWaitForUsableSingle;
    如果当前有1个可用,100线程同时借用时,都可以直接进入等待成功。

    lock;
    try
      lvObject := nil;
      if FUsableList.Count > 0 then
      begin
        lvObj := PObjectBlock(FUsableList[FUsableList.Count-1]);
        FUsableList.Delete(FUsableList.Count-1);
        FBusyList.Add(lvObj);
        lvObj.FBorrowTime := getTickCount;
        lvObj.FRelaseTime := 0;
        lvObject := lvObj.FObject;
      end else
      begin
        if GetCount >= FMaxNum then
        begin
          //如果当前有1个可用,100线程同时借用时,都可以直接(checkWaitForUsableSingle)成功。
          continue;
          //退出(unLock)后再进行等待....
          //raise exception.CreateFmt('超出对象池[%s]允许的范围[%d]', [self.ClassName, FMaxNum]);
        end;
        lvObject := createObject;
        if lvObject = nil then raise exception.CreateFmt('不能得到对象,对象池[%s]未继承处理createObject函数', [self.ClassName]);

        GetMem(lvObj, SizeOf(TObjectBlock));
        try
          ZeroMemory(lvObj, SizeOf(TObjectBlock));
        
          lvObj.FObject := lvObject;
          lvObj.FBorrowTime := GetTickCount;
          lvObj.FRelaseTime := 0;
          FBusyList.Add(lvObj);
        except
          lvObject.Free;
          FreeMem(lvObj, SizeOf(TObjectBlock));
          raise;
        end;
      end;

      //设置信号灯
      makeSingle;

      Result := lvObject;
      //获取到
      Break;
    finally
      unLock;
    end;
  end;
end;

procedure TMyObjectPool.makeSingle;
begin
  if (GetCount < FMaxNum)      //还可以创建
     or (FUsableList.Count > 0)  //还有可使用的
     then
  begin
    //设置有信号
    SetEvent(FUsableSingle);
  end else
  begin
    //没有信号
    ResetEvent(FUsableSingle);
  end;

  if FBusyList.Count > 0 then
  begin
    //没有信号
    ResetEvent(FReleaseSingle);
  end else
  begin
    //全部归还有信号
    SetEvent(FReleaseSingle)
  end;
end;

function TMyObjectPool.GetCount: Integer;
begin
  Result := FUsableList.Count + FBusyList.Count;
end;

procedure TMyObjectPool.lock;
begin
  FLocker.Enter;
end;

function TMyObjectPool.waitForReleaseSingle: Boolean;
var
  lvRet:DWORD;
begin
  Result := false;
  lvRet := WaitForSingleObject(FReleaseSingle, INFINITE);
  if lvRet = WAIT_OBJECT_0 then
  begin
    Result := true;
  end;
end;

procedure TMyObjectPool.checkWaitForUsableSingle;
var
  lvRet:DWORD;
begin
  lvRet := WaitForSingleObject(FUsableSingle, FTimeOut);
  if lvRet <> WAIT_OBJECT_0 then
  begin
    raise Exception.CreateFmt('对象池[%s]等待可使用对象超时(%d),使用状态[%d/%d]!',
      [FName, lvRet, getBusyCount, FMaxNum]);
  end;                                                                 
end;

end.

转载于:https://www.cnblogs.com/DKSoft/p/3564983.html

一个使用ADO连接池的示例,演示了TADOStoredProc动态参数的使用,带重连机制 =================== unit UnitDemo; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; //数据库服务器 gDBServer: String = '127.0.0.1'; //数据库名称 gDBName: String = 'master'; //数据库用户名 gDBUser: String = 'sa'; //密码 gDBPass: String = '2001'; implementation {$R *.dfm} uses ADODB, UnitADOConnectionPool; const CreateSQL = 'create procedure TestMyPool (@type sysname) '#13#10+ 'as'#13#10+ 'select * from sysobjects where xtype=@type'#13#10+ 'return @@rowcount'; DeleteSQL = 'if Exists(select 1 from sysobjects where xtype=N''P'' and name=N''TestMyPool'')'#13#10+ ' drop procedure TestMyPool'; var gPoolMan: TADOConnPoolMan = Nil; procedure TForm2.Button1Click(Sender: TObject); var ADOObject:TADOConnPoolObject; ADOStoredProc:TADOStoredProc; Running :Integer; I: Integer; begin //取得一个存储过程资源(含一数据库有效连接) ADOObject := gPoolMan.CreateSP('TestMyPool'); if ADOObject = Nil then //取得资源失败 Exit; try ADOStoredProc := ADOObject.ExecObject as TADOStoredProc; Running := 2;//允许重试(两次)操作,以便在操作失败之后达到重连 while Running>0 do begin Dec(Running); if ADOObject.NeedRefresh then begin//判断是否有重连标志(比如数据库断开等,可能需要进行重连) if Not ADOObject.Reconnect then Exit; ADOObject.NeedRefresh := Not ADOStoredProc.Parameters.Refresh; if ADOObject.NeedRefresh then Exit; end; for I := 1(*Zero is the *Result* Parameter*) to ADOStoredProc.Parameters.Count - 1 do begin //========================= //传递参数 ADOStoredProc.Parameters.Items[I].Value := 'U'; //========================= end; if Running 0 then try //执行存储过程 ADOStoredProc.Open; //执行存储过程成功,退出循环进入后续的数据处理 break; except On E:Exception do begin //执行失败非程序级的异常通常有两种可能: //1.数据库连接断开 //2.自适合的参数传递当中可能存储过程已更新,参与不一致 //设置重连标志 ADOObject.NeedRefresh := True; //=================== //这里记录数据库操作失败日志 //=================== end; end; Exit; end; //========================== //从ADOStoredProc当中读取记录 ShowMessage(IntToStr(ADOStoredProc.Parameters.ParamByName('Result').Value)); //========================== //关闭存储对象的资源 ADOStoredProc.Close; finally //调用结束,释放资源 ADOObject.Free; end; end; procedure TForm2.FormCreate(Sender: TObject); var ADOConn:TADOConnection; begin (****************BEGIN*******************) (*注:仅为测试准备 *) //初始化测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); ADOConn.Execute(CreateSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) //初始化连接池 gPoolMan := TADOConnPoolMan.Create(gDBServer,gDBUser,gDBPass,gDBName,true); end; procedure TForm2.FormDestroy(Sender: TObject); var ADOConn:TADOConnection; begin //释放连接池 if Assigned(gPoolMan) then gPoolMan.Free; (****************BEGIN*******************) (*注:仅为测试准备 *) //清理测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) end; end.
delphi线程池单元文件uThreadPool.pas,用法如下 type TRecvCommDataWorkItem=class(TWorkItem) public // updatetime,addtime:TDateTime; // orderid,ordertype,urljson,loadcount,savepath:string; url,Filename:string; total,order:Integer; _orderid:string; failedcount:Integer; IFCoverFile:Boolean; // 线程处理请求时触发的事件 procedure DealwithCommRecvData(Sender: TThreadsPool; WorkItem: TWorkItem; aThread: TProcessorThread); // 线程初始化时触发的事件 procedure TProcessorThreadInitializing(Sender: TThreadsPool; aThread:TProcessorThread); // 线程结束时触发的事件 procedure TProcessorThreadFinalizing(Sender: TThreadsPool; aThread:TProcessorThread); //任务队列空时触发的事件 procedure TQueueEmpty(Sender: TThreadsPool; EmptyKind: TEmptyKind); end; 先声明一个类 然后用法 FThreadPool := TThreadsPool.Create(nil); // 创建线程池 FThreadPool.ThreadsMin := 10; // 初始工作线程数 FThreadPool.ThreadsMax := 100; // 最大允许工作线程数 AWorkItem := TRecvCommDataWorkItem.Create; ISAllOverLoad:=False; AWorkItem.url:=urljson; AWorkItem.order:=i; AWorkItem.total:=JA.Count; AWorkItem.Filename:=savefilepath; AWorkItem._orderid:=orderid; AWorkItem.IFCoverFile:=IFCoverFile; FThreadPool.AddRequest(AWorkItem,True); // 向线程池分配一个任务 FThreadPool.OnProcessRequest := AWorkItem.DealwithCommRecvData; FThreadPool.OnThreadInitializing := AWorkItem.TProcessorThreadInitializing; FThreadPool.OnThreadFinalizing := AWorkItem.TProcessorThreadFinalizing; FThreadPool.OnQueueEmpty := AWorkItem.TQueueEmpty; 仔细看下线程池单元的函数说明轻松搞定。 procedure TRecvCommDataWorkItem.TQueueEmpty(Sender: TThreadsPool; EmptyKind: TEmptyKind); begin if EmptyKind=ekProcessingFinished then begin try if Assigned(geturl) then //存在的bug 如果下载文件存在的不行 begin //Sleep(200); //激活线程可能会发生在 休眠之前!! ISAl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值