Delphi版 环形无锁缓冲
2016-04-13 23:33
323 查看
{*******************************************************} { } { 环形无锁缓冲Delphi版 } { 2016.04.13 By Lance } { 联系方式QQ:286922468 } { } {*******************************************************} { 本源码受原作者节制,你可以任意复制、修改、使用,如发现 BUG请报告给我们。为了倡导开源,你的一切修改版本,我们 希望也能开源。 警告:使用本项目源码产生的一切后果由使用者自行负责。 注:TJsRingBuffer 基于寰子博客中C++源码,版权归原作者所有 寰子博客原文 http://blog.csdn.net/xocoder/article/details/7880769 } unit JsRingBuffer; {.$DEFINE DeBugLog} interface uses Windows; const XRING_BUFFER_READ_POS_AND_WRITE_POS_Size=2; type TJsRingBuffer=class private // FCS:TRTLCriticalSection; BufferData:array of Byte; BufferSize,FWritePosition,FReadPosition:DWord; function CopyDataWithAddReadPosOption(Dest:Pointer;DestSize,CopySize:DWord;AddReadPos:Bool):Bool; function PushData2(Data:Pointer;Size:DWord):Bool; function GetFreeSize():DWord; protected public function GetUsedSize():DWord; function PopData(Dest:Pointer;DestSize,PopSize:DWord):Bool; overload; function PopData(PopSize:DWord):Bool; overload; function PushData(Data:Pointer;Size:DWord):Bool; function CopyData(Dest:Pointer;DestSize,CopySize:DWord):Bool; public constructor Create(const Size:DWord); destructor Destroy; override; end; implementation constructor TJsRingBuffer.Create(const Size:DWord); begin inherited Create; // InitializeCriticalSection(FCS); BufferSize:=(Size+XRING_BUFFER_READ_POS_AND_WRITE_POS_Size); FWritePosition:=1; FReadPosition:=0; BufferData:=nil; SetLength(BufferData,BufferSize); // ZeroMemory(BufferData,BufferSize); end; destructor TJsRingBuffer.Destroy; begin SetLength(BufferData,0); // DeleteCriticalSection(FCS); inherited Destroy; end; function TJsRingBuffer.GetUsedSize():DWord; var readPos,writePos:DWord; begin readPos:=FReadPosition; writePos:=FWritePosition; if writePos>readPos then begin Result:=writePos-readPos-1; Exit; end else if (writePos<readPos) then begin Result:=(BufferSize-readPos-1)+FWritePosition; Exit; end else begin {$IFDEF DeBugLog} OutputDebugString(PChar('error:write pos equal read pos')); {$ENDIF} Result:=0; end; end; function TJsRingBuffer.GetFreeSize():DWord; var usedSize:DWord; begin usedSize:=GetUsedSize(); Result:=BufferSize-(usedSize+XRING_BUFFER_READ_POS_AND_WRITE_POS_Size); end; function TJsRingBuffer.PushData(Data:Pointer;Size:DWord):Bool; begin // EnterCriticalSection(FCS); Result:=PushData2(Data,Size); // LeaveCriticalSection(FCS); end; function TJsRingBuffer.PushData2(Data:Pointer;Size:DWord):Bool; var freeSize,readPos,writePos,lenFromWritePosToBufferEnd,secondPartLen:DWord; begin freeSize:=GetFreeSize(); if (freeSize<Size) then begin//空闲数不足,无法写入 Result:=False; Exit; end; readPos:=FReadPosition; writePos:=FWritePosition; if (writePos>readPos) then begin//写入在未读数据后面,初始化时,写入点为1,读取点为0 lenFromWritePosToBufferEnd:=BufferSize-writePos; if (Size<=lenFromWritePosToBufferEnd) then begin//写入的数据,未跨环 CopyMemory(Pointer(Integer(BufferData)+FWritePosition),Pointer(Integer(Data)),Size); Inc(FWritePosition,Size); if (FWritePosition=BufferSize) then begin //若写完数据后,新写入点刚好是在环最尾,就把写入点定位到环头 FWritePosition:=0 end else if (FWritePosition>BufferSize) then begin //若写完数据后,新写入点比环还大,出错处理 //这里应该不可能发生吧? Size<=lenFromWritePosToBufferEnd时,不可能出现这种情况 {$IFDEF DeBugLog} OutputDebugString(PChar('wirtepos cannot bigger than Size')); {$ENDIF} Result:=False; Exit; end; Result:=True; Exit; end else begin // 先拷贝前一部分到缓冲区尾部 CopyMemory(Pointer(Integer(BufferData)+FWritePosition),Pointer(Integer(Data)),lenFromWritePosToBufferEnd); secondPartLen:=Size-lenFromWritePosToBufferEnd; // 拷贝后一部分到缓冲区前部 CopyMemory(Pointer(Integer(BufferData)),Pointer(Integer(Data)+lenFromWritePosToBufferEnd),secondPartLen); FWritePosition:=secondPartLen; Result:=True; Exit; end; end else if (writePos<readPos) then begin CopyMemory(Pointer(Integer(BufferData)+writePos),Pointer(Integer(Data)),Size); Inc(FWritePosition,Size); Result:=True; Exit; end else begin {$IFDEF DeBugLog} OutputDebugString(PChar('error:write pos equal read pos')); {$ENDIF} Result:=False; Exit; end; end; function TJsRingBuffer.CopyData(Dest:Pointer;DestSize,CopySize:DWord):Bool; begin // EnterCriticalSection(FCS); Result:=CopyDataWithAddReadPosOption(Dest,DestSize,CopySize,False); // LeaveCriticalSection(FCS); end; function TJsRingBuffer.PopData(Dest:Pointer;DestSize,PopSize:DWord):Bool; begin // EnterCriticalSection(FCS); Result:=CopyDataWithAddReadPosOption(Dest,DestSize,popSize,True); // LeaveCriticalSection(FCS); end; function TJsRingBuffer.PopData(PopSize:DWord):Bool; begin // EnterCriticalSection(FCS); Result:=CopyDataWithAddReadPosOption(nil,0,PopSize,True); // LeaveCriticalSection(FCS); end; function TJsRingBuffer.CopyDataWithAddReadPosOption(Dest:Pointer;DestSize,CopySize:DWord;AddReadPos:Bool):Bool; var usedSize,writePos,readPos,lenFromReadPosToBufferEnd,secondPartLen:DWord; begin usedSize:=GetUsedSize(); if (usedSize<CopySize) then begin {$IFDEF DeBugLog} OutputDebugString(PChar('Data is not enought to copy')); {$ENDIF} Result:=False; Exit; end; if (Dest<>nil) then begin if (DestSize<CopySize) then begin {$IFDEF DeBugLog} OutputDebugString(PChar('Dest buffer Size is smaller than copy Size')); {$ENDIF} Result:=False; Exit; end; end; writePos:=FWritePosition; readPos:=FReadPosition; if (writePos>readPos) then begin//要读取得数据,未跨环 if (Dest<>nil) then begin CopyMemory(Pointer(Integer(Dest)),Pointer(Integer(BufferData)+readPos+1),CopySize); {$IFDEF DeBugLog} //读出数据后,清理无用的数据 if (addReadPos) then ZeroMemory(Pointer(Integer(BufferData)+readPos+1),CopySize); {$ENDIF} end; if (addReadPos) then Inc(FReadPosition,CopySize); Result:=True; Exit; end else if (writePos<readPos) then begin//要读取的数据,跨环 lenFromReadPosToBufferEnd:=BufferSize-readPos-1; if (CopySize<=lenFromReadPosToBufferEnd) then begin if (Dest<>nil) then begin CopyMemory(Pointer(Integer(Dest)),Pointer(Integer(BufferData)+readPos+1),CopySize); {$IFDEF DeBugLog} //读出数据后,清理无用的数据 if (addReadPos) then ZeroMemory(Pointer(Integer(BufferData)+readPos+1),CopySize); {$ENDIF} end; if (addReadPos) then begin inc(FReadPosition,CopySize); if not(FReadPosition<BufferSize) then begin {$IFDEF DeBugLog} OutputDebugString(PChar('FReadPosition => BufferSize')); {$ENDIF} Result:=False; Exit; end; end; Result:=True; Exit; end else begin secondPartLen:=CopySize-lenFromReadPosToBufferEnd; if (Dest<>nil) then begin CopyMemory(Pointer(Integer(Dest)),Pointer(Integer(BufferData)+readPos+1),lenFromReadPosToBufferEnd); CopyMemory(Pointer(Integer(Dest)+lenFromReadPosToBufferEnd),Pointer(Integer(BufferData)),secondPartLen); end; if (addReadPos) then FReadPosition:=secondPartLen-1; Result:=True; Exit; end; end else begin {$IFDEF DeBugLog} OutputDebugString(PChar('error:write pos equal read pos')); {$ENDIF} Result:=False; Exit; end; end; end.
相关文章推荐
- Delphi 10.1 柏林更新内容简译
- Delphi 给结构体指针分配内存,用new(p),释放用dispose(p)
- Delphi MDI程序 父窗体如何调用当前活动子窗体的函数/过程
- Delphi中实现MDI子窗体(转)
- Delphi动态调用C++写的DLL
- Delphi exe + bpl 简述
- delphi 712 Word 2
- Delphi版本号对照
- Delphi 的运算符列表
- Delphi exe动态调用加载bpl 报地址错误的解决方法
- delphi bpl插件系统开发(转)
- Delphi指针相关的操作符
- Delphi调用动态库
- Delphi RxRichEdit高级操作
- delphi 怎么把image上的图片粘贴到剪切板上
- delphi 中 image 控件加载bmp、JPG、GIF、PNG等图片的办法
- Delphi 保存写字板程序, 并进行打印
- Delphi中使用GDI+进行绘图(2)
- Delphi中使用GDI+进行绘图(1)
- Delphi/C#之父首次访华:55岁了 每天都写代码