Delphi의 FIFO 실현

9827 단어 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.


좋은 웹페이지 즐겨찾기