zoukankan      html  css  js  c++  java
  • Delphi的FIFO实现

    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.
    

      

  • 相关阅读:
    swfupdate flash上传工具
    在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服 务器。请验证实例名称是否正确并且 SQL Server 已配置为允
    多对多 一对一 一对多 主从 关联 字典
    JavaScript面向对象
    vue的transition过渡效果
    【译】Learn ES2015——箭头函数
    vue的选项
    JavaScript模块化
    vue-router
    vuex是啥
  • 原文地址:https://www.cnblogs.com/hezihang/p/3654516.html
Copyright © 2011-2022 走看看