DIOCP开源项目出炉,附带<IOCP退出资源的管控研究代码>

经过对一段时间对IOCP的学习和研究。对IOCP的流程有了一定的了解。

后面对一段时间的IOCP优化和实际项目的使用,在DIOCP中加入了日志文件记录功能,利用api编写了一个客户端通信类,等解决了很多bug,并已使用在公司的项目中,现运行稳定。今天对IOCP退出时资源的释放,做了最后一步研究和优化。

 

 

为了方便大家学习,我把这个项目命名为DIOCP,上传在google的SVN项目中

https://code.google.com/p/diocp/

大家可以通过svn下载代码,里面我写了一个Echo的测试Demo,准备后续加入聊天等Demo。

特地为DIOCP开设了一个群:320641073,欢迎学习的IOCP的童鞋进入讨论。

--IOCP退出资源的管控研究

现在在项目中使用的IOCP退出的过程是。

procedure TIOCPConsole.close;
begin
  //关闭服务端端口
  FIOCPObject.closeSSocket;

  //停止监听
  stopListener;

  //断开所有连接
  FIOCPObject.DisconnectAllClientContext;

  //等待资源的回归
  FIOCPObject.WaiteForResGiveBack;

  //停止工作线程
  stopWorkers;

  //标志状态
  FActive := false;
end;

 

 

对IO内存池也进行了一些优化,主要加入了资源回归的监控 

unit uMemPool;

interface

uses
  JwaWinsock2, Windows, SyncObjs, uIOCPProtocol;


type
  TIODataMemPool = class(TObject)
  private
    //全部归还的信号灯
    FCanCloseSingle: THandle;

    FCs: TCriticalSection;

    //第一个可用的内存块
    FHead: POVERLAPPEDEx;

    //最后一个可用的内存卡
    FTail: POVERLAPPEDEx;

    //可用的内存个数
    FUseableCount:Integer;

    //正在使用的个数
    FUsingCount:Integer;

    /// <summary>
    ///   将一个内存块添加到尾部
    /// </summary>
    /// <param name="pvIOData"> (POVERLAPPEDEx) </param>
    procedure AddData2Pool(pvIOData:POVERLAPPEDEx);

    /// <summary>
    ///   得到一块可以使用的内存
    /// </summary>
    /// <returns> POVERLAPPEDEx
    /// </returns>
    function getUsableData: POVERLAPPEDEx;

    /// <summary>
    ///   创建一块内存空间
    /// </summary>
    /// <returns> POVERLAPPEDEx
    /// </returns>
    function InnerCreateIOData: POVERLAPPEDEx;

    procedure clearMemBlock(pvIOData:POVERLAPPEDEx);

    //释放所有的内存块
    procedure FreeAllBlock;
  public
    class function instance: TIODataMemPool;
    constructor Create;
    destructor Destroy; override;

    function waiteForGiveBack: Boolean;

    //借一块内存
    function borrowIOData: POVERLAPPEDEx;

    //换会一块内存
    procedure giveBackIOData(const pvIOData: POVERLAPPEDEx);

    function getCount: Cardinal;
    function getUseableCount: Cardinal;
    function getUsingCount:Cardinal;

  end;

implementation

uses
  uIOCPFileLogger;

var
  __IODATA_instance:TIODataMemPool;

constructor TIODataMemPool.Create;
begin
  inherited Create;
  FCs := TCriticalSection.Create();
  FUseableCount := 0;
  FUsingCount := 0;
  FCanCloseSingle := CreateEvent(nil, True, True, nil);
end;

destructor TIODataMemPool.Destroy;
begin
  CloseHandle(FCanCloseSingle);
  FreeAllBlock;
  FCs.Free;
  inherited Destroy;
end;

{ TIODataMemPool }

procedure TIODataMemPool.AddData2Pool(pvIOData:POVERLAPPEDEx);
begin
  if FHead = nil then
  begin
    FHead := pvIOData;
    FHead.next := nil;
    FHead.pre := nil;
    FTail := pvIOData;
  end else
  begin
    FTail.next := pvIOData;
    pvIOData.pre := FTail;
    FTail := pvIOData;
  end;
  Inc(FUseableCount);
end;

function TIODataMemPool.InnerCreateIOData: POVERLAPPEDEx;
begin
  Result := POVERLAPPEDEx(GlobalAlloc(GPTR, sizeof(OVERLAPPEDEx)));

  GetMem(Result.DataBuf.buf, MAX_OVERLAPPEDEx_BUFFER_SIZE);

  Result.DataBuf.len := MAX_OVERLAPPEDEx_BUFFER_SIZE;

  //清理一块内存
  clearMemBlock(Result);
end;

function TIODataMemPool.borrowIOData: POVERLAPPEDEx;
begin
  FCs.Enter;
  try
    Result := getUsableData;
    if Result = nil then
    begin
      //生产一个内存块
      Result := InnerCreateIOData;

      //直接借走<增加使用计数器>
      Inc(FUsingCount);
    end;

    //变成没有信号
    if FUsingCount > 0 then
      ResetEvent(FCanCloseSingle);

  finally
    FCs.Leave;
  end;
end;

procedure TIODataMemPool.clearMemBlock(pvIOData: POVERLAPPEDEx);
begin
  //清理一块内存
  pvIOData.IO_TYPE := 0;

  pvIOData.WorkBytes := 0;
  pvIOData.WorkFlag := 0;

  //ZeroMemory(@pvIOData.Overlapped, sizeof(OVERLAPPED));

  //还原大小<分配时的大小>
  pvIOData.DataBuf.len := MAX_OVERLAPPEDEx_BUFFER_SIZE;

  //ZeroMemory(pvIOData.DataBuf.buf, pvIOData.DataBuf.len);
end;

procedure TIODataMemPool.FreeAllBlock;
var
  lvNext, lvData:POVERLAPPEDEx;
begin
  lvData := FHead;
  while lvData <> nil do
  begin
    //记录下一个
    lvNext := lvData.next;

    //释放当前Data
    FreeMem(lvData.DataBuf.buf, lvData.DataBuf.len);
    GlobalFree(Cardinal(lvData));

    //准备释放下一个
    lvData := lvNext;
  end;

  FHead := nil;
  FTail := nil;

  FUsingCount := 0;
  FUseableCount := 0; 

end;

function TIODataMemPool.getCount: Cardinal;
begin
  Result := FUseableCount + FUsingCount;
end;

procedure TIODataMemPool.giveBackIOData(const pvIOData:
    POVERLAPPEDEx);
begin
  FCs.Enter;
  try
    if (pvIOData.pre <> nil) or (pvIOData.next <> nil) or (pvIOData = FHead) then
    begin
      TIOCPFileLogger.logErrMessage('回收内存块是出现了异常,该内存块已经回收!');

    end else
    begin
      //清理内存块
      clearMemBlock(pvIOData);

      //加入到可以使用的内存空间
      AddData2Pool(pvIOData);

      //减少使用计数器
      Dec(FUsingCount);
    end;

    //有信号
    if FUsingCount = 0 then SetEvent(FCanCloseSingle);
  finally
    FCs.Leave;
  end;
end;

function TIODataMemPool.getUsableData: POVERLAPPEDEx;
var
  lvPre:POVERLAPPEDEx;
begin
  if FTail = nil then
  begin
    Result := nil;
  end else  
  begin   
    Result := FTail;

    lvPre := FTail.pre;
    if lvPre <> nil then
    begin
      lvPre.next := nil;
      FTail := lvPre;
    end else  //FTail是第一个也是最后一个,只有一个
    begin
      FHead := nil;
      FTail := nil;
    end;  

    Result.next := nil;
    Result.pre := nil;

    Dec(FUseableCount);
    Inc(FUsingCount);
  end;
end;

function TIODataMemPool.getUseableCount: Cardinal;
begin
  Result := FUseableCount;
end;

function TIODataMemPool.getUsingCount: Cardinal;
begin
  Result := FUsingCount;
end;

class function TIODataMemPool.instance: TIODataMemPool;
begin
  Result := __IODATA_instance;
end;

function TIODataMemPool.waiteForGiveBack: Boolean;
var
  lvRet:DWORD;
begin
  Result := false;
  lvRet := WaitForSingleObject(FCanCloseSingle, INFINITE);
  if lvRet = WAIT_OBJECT_0 then
  begin
    Result := true;
  end;
end;


initialization
  __IODATA_instance := TIODataMemPool.Create;

finalization
  if __IODATA_instance <> nil then
  begin
    __IODATA_instance.Free;
    __IODATA_instance := nil;
  end;

end.

 

posted @ 2013-05-18 16:26  D10.天地弦  阅读(1784)  评论(0编辑  收藏  举报