一个简易无锁池

一个简易 无锁池

1.所有读写无等待,不需要判断条件直接读写(除自动扩充容量时),效率是一般带锁或带条件判断池的两倍以上。

2.预先开辟2的幂大小容量,可自增,每次翻倍

3.仅提供思路,工程应用可靠性还不确定。

 

// 无锁池

// hezihang @cnblogs.com



//20140609 增加Grow临界区,减少等待时间

//20140608 修正可能存在同时Grow的Bug



unit utAtomPool;



interface



Uses

  SysUtils,

  SyncObjs;



Type

  Int32 = Integer;

  UInt32 = Cardinal;



  TAtomPoolAbstract = Class

  private

    FWritePtr: Int32;

    FReadPtr: Int32;

    FHighBound: UInt32;

    FData: array of Pointer;

    FCs: TCriticalSection;

    FLock: Int32;

    //FCheckThread: Integer;

    procedure CheckGrow;inline;

  Protected

    function AllocItemResource: Pointer; virtual; abstract;

    procedure FreeItemResource(Item: Pointer); virtual; abstract;

    function GetSize: UInt32;

    procedure AllocResources;

    procedure FreeResources;

    procedure Grow;inline;

  Public

    function Get: Pointer;

    procedure Put(Item: Pointer);

    Constructor Create(Size: UInt32); Virtual;

    Destructor Destroy; Override;

    property Size: UInt32 read GetSize;

  End;



  TAtomPoolMem4K = class(TAtomPoolAbstract)

    function AllocItemResource: Pointer; override;

    procedure FreeItemResource(Item: Pointer); override;

  end;



Implementation



{$IF defined(WIN32) or defined(WIN64)}



uses Windows;

{$ELSE}

{$I InterlockedAPIs.inc}

{$ENDIF}



const

  MAXTHREADCOUNT = 1000; // 从池中申请资源最大线程数

  // 创建池,大小必须是2的幂,并且必须大于MAXTHREADCOUNT



Constructor TAtomPoolAbstract.Create(Size: UInt32);

var

  OK: Boolean;

Begin

  Inherited Create;

  OK := (Size and (Size - 1) = 0);

  OK := OK and (Size > MAXTHREADCOUNT);



  if not OK then

    raise Exception.Create(Format('池长度必须大于%d并为2的幂', [MAXTHREADCOUNT]));

  FCs := TCriticalSection.Create;

  try

    SetLength(FData, Size);

    FHighBound := Size - 1;

    FWritePtr := FHighBound;

    FReadPtr := 0;

  except

    Raise Exception.Create('池申请内存失败');

  end;

End;



Destructor TAtomPoolAbstract.Destroy;

Begin

  FreeResources;

  SetLength(FData, 0);

  FCs.Free;

  Inherited;

End;



procedure TAtomPoolAbstract.AllocResources;

var

  i: UInt32;

begin

  for i := 0 to FHighBound do

    FData[i] := AllocItemResource;

end;



procedure TAtomPoolAbstract.FreeResources;

var

  i: UInt32;

begin

  for i := FHighBound downto 0 do

    Self.FreeItemResource(FData[i]);

end;



procedure TAtomPoolAbstract.CheckGrow;

begin

  if FLock > 0 then

  begin

    while FLock = 1 do

      Sleep(0);

    FCs.Enter;

    FCs.Leave;

  end;

end;



procedure TAtomPoolAbstract.Put(Item: Pointer);

var

  N: UInt32;

begin

  CheckGrow;

  N := InterlockedIncrement(FWritePtr);

  FData[N and FHighBound] := Item;

end;



Function TAtomPoolAbstract.Get: Pointer;

var

  N, M, K: UInt32;

begin

  N := FWritePtr and FHighBound;

  M := FReadPtr and FHighBound;

  K := (M + MAXTHREADCOUNT) and FHighBound;

  if ((N > M) and (N < K)) or ((N < M) and (N > K)) then

  begin

    Grow

  end;



  N := InterlockedIncrement(FReadPtr);

  Result := FData[N and FHighBound];

end;



function TAtomPoolAbstract.GetSize: UInt32;

begin

  Result := FHighBound + 1;

end;



procedure TAtomPoolAbstract.Grow;

var

  i, N: Integer;

begin

  if InterlockedCompareExchange(FLock, 1, 0)=0 then

  begin

    FCs.Enter;

    InterlockedIncrement(FLock);

    N := Length(FData);

    SetLength(FData, N + N);

    for i := N to High(FData) do

      FData[i] := AllocItemResource;

    InterlockedIncrement(FLock);

    //Sleep(MAXTHREADCOUNT * 4);

    // while (FCheckThread<MAXTHREADCOUNT) do Sleep(0);

    FHighBound := High(FData);

    //FCheckThread := 0;

    FCs.Leave;

    InterlockedExchange(FLock, 0);

  end

  else

    CheckGrow;

end;



{ TAtomPoolMem4K }



function TAtomPoolMem4K.AllocItemResource: Pointer;

begin

  GetMem(Result, 4096);

end;



procedure TAtomPoolMem4K.FreeItemResource(Item: Pointer);

begin

  FreeMem(Item, 4096);

end;



End.

 

你可能感兴趣的:(锁)