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

简介: 经过对一段时间对IOCP的学习和研究。对IOCP的流程有了一定的了解。 后面对一段时间的IOCP优化和实际项目的使用,在DIOCP中加入了日志文件记录功能,利用api编写了一个客户端通信类,等解决了很多bug,并已使用在公司的项目中,现运行稳定。

经过对一段时间对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.

 

目录
相关文章
|
6月前
|
缓存 算法 Java
Linux内核新特性年终大盘点-安卓杀后台现象减少的背后功臣MGLRU算法简介
MGLRU是一种新型内存管理算法,它的出现是为了弥补传统LRU(Least Recently Used)和LFU(Least Frequently Used)算法在缓存替换选择上的不足,LRU和LFU的共同缺点就是在做内存页面替换时,只考虑内存页面在最近一段时间内被访问的次数和最后一次的访问时间,但是一个页面的最近访问次数少或者最近一次的访问时间较早,可能仅仅是因为这个内存页面新近才被创建,属于刚刚完成初始化的年代代页面,它的频繁访问往往会出现在初始化之后的一段时间里,那么这时候就把这种年轻代的页面迁移出去
|
6月前
|
消息中间件 并行计算 网络协议
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
探秘高效Linux C/C++项目架构:让进程、线程和通信方式助力你的代码飞跃
159 0
|
6月前
|
XML JSON API
软件吞噬世界,Api快速入门到放弃
软件吞噬世界,Api快速入门到放弃
|
存储 网络安全 开发者
“申诉无门”,开源开发者一怒之下宣布停止开发并关闭所有项目
“在谷歌错误地将 FairEmail 标记为间谍软件而没有给出合理的上诉机会后,我的所有项目都已终止。在解决此问题之前,将不会有进一步的开发和支持。”近日,开源电子邮件客户端 FairEmail 的开发者 Marcel Bokhorst 从谷歌应用商店 Google Play 下架了他所有的应用程序,并宣布将停止开发和维护它们,包括一款受欢迎的开源防火墙应用 Netguard。
159 0
“申诉无门”,开源开发者一怒之下宣布停止开发并关闭所有项目
|
Rust
GitHub 项目持续本地化,交给它来做,准没错!
不知道你们有没有在 GitHub 上看到过一些项目,它的一份项目文档被翻译成了多国语言的版本。
248 0
GitHub 项目持续本地化,交给它来做,准没错!
|
JSON 监控 jenkins
文未有福利 | 接口自动化你不懂?听HttpRunner的作者怎么说
HttpRunner最让我们惊喜的是HttpRunner简单易用。它做到了工具集成,也有自己的核心技术,就像requests代码和HttpRunner的YAML文件,你可以无缝切换。 它是一款面向 HTTP(S) 协议的通用测试框架,你确实只需编写维护一份YAML/JSON脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。那么首先我们需要问一下,HttpRunner是什么
|
架构师 Unix 应用服务中间件
PowerShell 主架构师:我用业余时间开发项目,表现优秀反而被微软降级了
经过两年多的时间,微软在 5 月 3 日宣布对用于 Visual Studio Code 的 PowerShell 扩展进行了一次重大更新,是对 PowerShell Editor Services 的核心 PowerShell 引擎的彻底改造。
141 0
|
定位技术 开发者 Python
保姆级教程带你开发优质的Python库之中篇【命令行发行】
正式的Python专栏第10篇,同学站住,别错过这个从0开始的文章!
167 0
保姆级教程带你开发优质的Python库之中篇【命令行发行】
|
JSON 监控 jenkins
文未有福利 | 接口自动化你不懂?听HttpRunner的作者怎么说
文未有福利 | 接口自动化你不懂?听HttpRunner的作者怎么说
|
测试技术
带你读《基于模型的测试:一个软件工艺师的方法》之三:决策表
本书主要讨论基于模型的测试(MBT)技术。作为一门手艺而非艺术,其关键在于:对被测软件或系统的理解,选择合适工具的能力,以及使用这些工具的经验。围绕这三个方面,书中不仅综合阐述了MBT的理论知识及工具,而且分享了作者的实战经验。