FIFO主要用于多个不同线程或进程之间数据交换时做缓冲区用,尤其适合实时数据通讯应用中的数据缓冲,接收线程(进程)将数据写入FIFO,处理线程(进程)从FIFO取出数据
本单元中:
TMemoryFIFO类适用于单进程内不同线程之间交换数据
TMapFileFIFO类适用于不同进程之间交换数据
Unit UtFIFO;
Interface
Uses
Windows,
SysUtils,
SyncObjs;
Type
PFIFOStruct= ^TFIFOStruct;
TFIFOStruct= Record
FSize: Integer;
FWritePtr: Integer;
FReadPtr: Integer;
FBuffer: TByteArray;
End;
TFIFOReadFunc= Function(Buf: Pointer; Count: Integer): Integer;
TFIFOReadFuncOfObject= Function(const Buf; Count: Integer): Integer Of Object;
TAbstractFIFO= Class
Protected
FSelfAccess: Boolean;
FDataStruct: PFIFOStruct; // 数据区指针
Procedure AllocateResource(Size: Integer); Virtual; Abstract;
Procedure FreeResources; Virtual; Abstract;
Procedure Lock; Virtual; Abstract;
Procedure UnLock; Virtual; Abstract;
Public
Function FIFOFreeSpace: Integer;
Function FIFOUsedSpace: Integer;
Function CheckFIFOFull: Boolean;
Function CheckFIFOEmpty: Boolean;
Function WriteData(const Buf: Pointer; Count: Integer): Integer; Virtual;
Function ReadData(Buf: Pointer; Count: Integer): Integer; Virtual;
Function ReadDataByFunc(Func: TFIFOReadFuncOfObject;
Count: Integer): Integer; Virtual;
Constructor Create(Size: Integer); Virtual;
Destructor Destroy; Override;
Procedure Empty;
Function Size: Integer;
End;
TMemoryFIFO= Class(TAbstractFIFO)
Protected
FLocker: TCriticalSection;
Procedure AllocateResource(Size: Integer); Override;
Procedure FreeResources; Override;
Procedure Lock; Override;
Procedure UnLock; Override;
Public
Constructor Create(Size: Integer); Override;
Destructor Destroy; Override;
End;
TFileMapFIFO= Class(TAbstractFIFO)
Private
FMaster:Boolean;
FMapHandle: THandle; // 内存映射文件句柄
FMutexHandle: THandle; // 互斥句柄
FMapName: String; // 内存映射对象
FPVHandle: THandle;
Protected
Procedure AllocateResource(Size: Integer); Override;
Procedure FreeResources; Override;
Procedure Lock; Override;
Procedure UnLock; Override;
Public
Constructor Create(Const MapName: String; Size: Integer;bMaster:Boolean); Overload;
Destructor Destroy; Override;
Function WriteData(const Buf: Pointer; Count: Integer): Integer; Override;
Function ReadData(Buf: Pointer; Count: Integer): Integer; Override;
property PVHandle:NativeUInt read FPVHandle;
End;
Implementation
Function Min(Const A, B: Integer): Integer; inline;
begin
if A>B then Result:=B else Result:=A
end;
Constructor TAbstractFIFO.Create(Size: Integer);
Begin
Inherited Create;
AllocateResource(Size);
If Not Assigned(FDataStruct) Then
Raise Exception.Create('FIFO申请内存失败');
End;
Destructor TAbstractFIFO.Destroy;
Begin
FreeResources;
Inherited;
End;
Function TAbstractFIFO.FIFOFreeSpace;
Begin
With FDataStruct^ Do
Begin
Lock;
If FWritePtr> FReadPtr Then
Result:= (FSize- FWritePtr)+ FReadPtr- 1
Else
If FWritePtr< FReadPtr Then
Result:= FReadPtr- FWritePtr- 1
Else
Result:= FSize;
UnLock;
End;
End;
Function TAbstractFIFO.FIFOUsedSpace;
Begin
With FDataStruct^ Do
Begin
Lock;
If FWritePtr> FReadPtr Then
Result:= FWritePtr- FReadPtr
Else
If FWritePtr< FReadPtr Then
Result:= (FSize- FReadPtr)+ FWritePtr
Else
Result:= 0;
UnLock;
End;
End;
Function TAbstractFIFO.CheckFIFOFull: Boolean;
Begin
With FDataStruct^ Do
Begin
Lock;
If (FWritePtr= FSize- 1)And (FReadPtr= 0) Then
Result:= True
Else
If (FWritePtr+ 1= FReadPtr) Then
Result:= True
Else
Result:= False;
UnLock;
End;
End;
Function TAbstractFIFO.CheckFIFOEmpty: Boolean;
Begin
With FDataStruct^ Do
Begin
Lock;
Result:= (FWritePtr= FReadPtr);
UnLock;
End;
End;
Function TAbstractFIFO.WriteData(const Buf: Pointer; Count: Integer): Integer;
Var
N: Integer;
Begin
Result:= 0;
If Count<= 0 Then
Exit;
With FDataStruct^ Do
Begin
Lock;
If FWritePtr< FReadPtr Then //如果没有满或已满
Begin
Result:= Min(Count, FReadPtr- FWritePtr- 1);
Move(Buf^, FBuffer[FWritePtr], Result);
FWritePtr:= (FWritePtr+ Result)Mod FSize;
End
Else
If FWritePtr = FReadPtr Then //Buffer 空
Begin
Result:= Min(Count, FSize- 1);
Move(Buf^, FBuffer[0], Result);
FWritePtr:= Result;
FReadPtr:= 0;
End
Else
Begin
Result:= Min(Count, FSize- FWritePtr);
Move(Buf^, FBuffer[FWritePtr], Result);
if Result=Count then FWritePtr:= (FWritePtr+ Result) Mod FSize
else
Begin
N:= Min(Count- Result, FReadPtr);
Move(PByteArray(Buf)^[Result], FBuffer[0], N);
FWritePtr:= N;
Result:= Result+ N;
End;
End;
UnLock;
End;
End;
Function TAbstractFIFO.ReadData(Buf: Pointer; Count: Integer): Integer;
Var
N: Integer;
Begin
Result:= 0;
If Count<= 0 Then
Exit;
With FDataStruct^ Do
Begin
Lock;
If FReadPtr< FWritePtr Then
Begin
Result:= Min(Count, FWritePtr- FReadPtr);
Move(FBuffer[FReadPtr], Buf^, Result);
FReadPtr:= (FReadPtr+ Result)Mod FSize;
End
Else if FReadPtr>FWritePtr Then
Begin
Result:= Min(Count, FSize- FReadPtr);
Move(FBuffer[FReadPtr], Buf^, Result);
if Result=Count then FReadPtr:=(FReadPtr+Result) mod FSize
else
Begin
N:= Min(Count- Result, FWritePtr);
Move(FBuffer[0], PByteArray(Buf)[Result], N);
FReadPtr:= N;
Result:= Result+ N;
End;
End;
UnLock;
End;
End;
Function TAbstractFIFO.ReadDataByFunc(Func: TFIFOReadFuncOfObject;
Count: Integer): Integer;
Var
N, M: Integer;
Begin
Result:= 0;
If Count<= 0 Then
Exit;
With FDataStruct^ Do
Begin
Lock;
Try
If FReadPtr< FWritePtr Then
Begin
Result:= Func(FBuffer[FReadPtr], Min(Count, FWritePtr- FReadPtr));
FReadPtr:= (FReadPtr+ Result)Mod FSize;
End
Else if FReadPtr>FWritePtr Then
Begin
Result:= Func(FBuffer[FReadPtr], Min(Count, FSize- FReadPtr));
if Result=Count then FReadPtr:=(FReadPtr+Result) mod FSize
else
Begin
N:= Func(FBuffer[0], Min(Count- Result, FWritePtr));
FReadPtr:= N;
Result:= Result+ N;
End;
End;
Finally
UnLock;
End;
End;
End;
Procedure TAbstractFIFO.Empty;
Begin
Lock;
With FDataStruct^ Do
Begin
FWritePtr:= 0;
FReadPtr:= 0;
End;
UnLock;
End;
Function TAbstractFIFO.Size: Integer;
Begin
Result:= FDataStruct^.FSize- 1;
End;
Constructor TMemoryFIFO.Create(Size: Integer);
Begin
Inherited Create(Size);
FLocker:= TCriticalSection.Create;
End;
Destructor TMemoryFIFO.Destroy;
Begin
FLocker.Free;
Inherited;
End;
Procedure TMemoryFIFO.AllocateResource(Size: Integer);
Begin
Inherited;
GetMem(FDataStruct, Size+ 3* Sizeof(Integer));
With FDataStruct^ Do
Begin
FSize:= Size;
FWritePtr:= 0;
FReadPtr:= 0;
End;
End;
Procedure TMemoryFIFO.FreeResources;
Begin
FreeMem(FDataStruct, FDataStruct^.FSize+ 3* Sizeof(Integer));
Inherited;
End;
Procedure TMemoryFIFO.Lock;
Begin
FLocker.Enter;
End;
Procedure TMemoryFIFO.UnLock;
Begin
FLocker.Leave;
End;
// 构造函数
Constructor TFileMapFIFO.Create(Const MapName: String; Size: Integer;bMaster:Boolean);
Begin
FMapName:= MapName;
FMaster:=bMaster;
Inherited Create(Size);
End;
Destructor TFileMapFIFO.Destroy;
Begin
CloseHandle(FPVHandle);
Inherited;
End;
Procedure TFileMapFIFO.AllocateResource(Size: Integer);
Begin
Inherited;
if FMaster then
begin
FMapHandle:= CreateFileMapping($FFFFFFFF, Nil, PAGE_READWRITE, 0,
Size+ 3* Sizeof(Integer), PChar(FMapName));
If (FMapHandle= INVALID_HANDLE_VALUE)Or (FMapHandle= 0) Then
Raise Exception.Create('创建文件映射对象失败!');
end
else
FMapHandle:=OpenFileMapping(FILE_MAP_ALL_ACCESS,False,PChar(FMapName));
FDataStruct:= MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// 创建互斥对象,在写文件映射空间时用到它,以保持数据同步
FMutexHandle:= Windows.CreateMutex(Nil, False, PChar(FMapName+ '.Mtx'));
FPVHandle := CreateEvent(nil,True,False,PChar(FMapName + '.PV'));
If (FMutexHandle= 0)or(FPVHandle = 0) Then
Raise Exception.Create('创建互斥对象失败');
// 判断是否已经建立文件映射了
If (FMapHandle <> 0)And (GetLastError = ERROR_ALREADY_EXISTS) Then
Begin
End
Else
Begin
FillChar(FDataStruct^, Size+ 3* Sizeof(Integer), 0);
FDataStruct^.FSize:= Size;
End
End;
Procedure TFileMapFIFO.FreeResources;
Begin
UnmapViewOfFile(FDataStruct);
CloseHandle(FMutexHandle);
CloseHandle(FMapHandle);
Inherited;
End;
Procedure TFileMapFIFO.Lock;
Begin
WaitForSingleObject(FMutexHandle, INFINITE); // =WAIT_OBJECT_0)
End;
Procedure TFileMapFIFO.UnLock;
Begin
ReleaseMutex(FMutexHandle);
End;
Function TFileMapFIFO.WriteData(const Buf: Pointer; Count: Integer): Integer;
Begin
Lock;
Result:= Inherited WriteData(Buf, Count);
SetEvent(FPVHandle);
UnLock;
End;
Function TFileMapFIFO.ReadData(Buf: Pointer; Count: Integer): Integer;
Begin
Lock;
Result:= Inherited ReadData(Buf, Count);
UnLock;
End;
End.