程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi的FIFO實現

Delphi的FIFO實現

編輯:Delphi

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.

  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved