• 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.
  • 相关阅读:
    App界面设计利器Sketch 精选案例合集
    破解有道词典在线翻译接口--python
    欧几里得算法/欧几里得扩展算法-python
    深浅拷贝--python(预习中随手写的。因为当时很无聊。。。)
    为tomcat动态添加jndi数据源信息
    四个年头
    使用Node.JS访问Hyperledger Fabric的gRPC服务
    Hyperledger fabric Client Node.js Hello World示例程序
    在IBM Bluemix上部署Hyperledger应用
    Hyperledger区块数据的访问
  • 原文地址:https://www.cnblogs.com/DKSoft/p/3085572.html
Copyright © 2020-2023  润新知