DIOCP 소스 오픈 프로젝트 - Delphi 고성능 잠금 해제 대기열 (lock-free)

8649 단어 Delphi
최근에는 DIOCP에 임무 스케줄링 라인을 추가하려고 하는데, DIOCP의 업무 라인은 생산자(producer)가 받아들인 데이터 대상으로 임무 스케줄링 라인에 배달하여 통일적으로 분배한다.그러나 이 모든 것은 하나의 대열이 필요하다. 요 며칠 동안 자물쇠가 없는 대열에 주목하고 있다.
 
[대기열]
먼저 하나의 대기열이다. 간단한 대기열은 생산자가 데이터를 대기열(push)에 넣고 소비자가 대기열을 통해 데이터를 출력하여 처리하는 것이다.
간단한 대기열은 Push와 Pop 함수를 제공하는 것입니다.
우리는 체인 테이블로 데이터를 저장한다.Head ->data01->data02...data_n->Tail, 각 블록의 구조는 다음과 같습니다.
type
  PVarQueueBlock = ^TVarQueueBlock;
  TVarQueueBlock = packed record
    value:Variant;
    next:PVarQueueBlock;
  end;

 
1. Push 데이터 압입 시 압입 Tail.next는 새로 눌린 블록을 가리키고 새로운 블록으로 Tail을 만듭니다
procedure TSimpleQueue.pushQueue(pvData: PVarQueueBlock);
begin
  if FHead = nil then
  begin
    FHead = pvData;
    FTail := FHead;
  end else
  begin
    FTail.next := pvData;
    FTail := pvData;
  end;
  Inc(FCount);
end;

 
 
2. Pop 데이터를 진행할 때 Head 블록을 꺼내고 Head 블록으로 가리키는 다음 블록을 Head로 한다.
function TSimpleQueue.popQueue: PVarQueueBlock;
var
  lvTemp, lvRet:PVarQueueBlock;
begin
  lvTemp := FHead;
  if (lvTemp = nil) then
  begin        //      Pop   
    Result := nil;
    exit;
  end;

  //
  FHead := FHead.next;

  Dec(FCount);
  Result :=lvTemp;
end;

 
위에는 간단한 대열입니다.
 
[잠금 큐 없음]
위에서 실현된 대열은 다선정 상황에서 안전하지 않다.많은 대기열에서 자물쇠를 추가하려면push와 pop에서 자물쇠를 추가하는 것도 방법이다.임계를 바로 쓰면 되지만 우리가 해야 할 일은 자물쇠가 없는 대열이다
 
우선 다중 병렬 설계 규칙을 기억해라: 어떤 코드가 연속적으로 실행될 것이라고 가정해서는 안 된다
 
위의push 조작
FTail.next := pvData;
FTail := pvData;


아마도 FTAil을 실행했을 거예요.xt:=pvData 후 다른 라인에 뺏기고 FTAil에서 새로운 값을 부여합니다. 이렇게 FTAil:=pvData를 진행합니다.이렇게 하면 전체 데이터 체인이 파괴될 것이다.
만약 이 두 줄을 우리가 한 번에 완성할 수 있다면, 이렇게 하면 자물쇠가 없는 조작을 실현할 수 있을 것이다. 이렇게 하면 우리는 원자 조작을 도입해야 한다.Interlocked의 함수입니다.
 
자물쇠가 없다고 하는 것은 사실 그다지 확실하지 않다. 단지 자물쇠의 입도가 작을 뿐이다.우리는api의InterlockedCompareExchange 함수를 사용하여 실현하였다.
MSDN 찾아보세요.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560(v=vs.85).aspx
LONG __cdecl InterlockedCompareExchange(
  _Inout_  LONG volatile *Destination,
  _In_     LONG Exchange,
  _In_     LONG Comparand
);

Parameters
Destination [in, out]
A pointer to the destination value.
Exchange [in]
The exchange value.
Comparand [in]
The value to compare to Destination.
Return value
The function returns the initial value of the Destination parameter.
 
대충 해명하다.이 함수는 비교한 후에 교환한다.첫 번째 파라미터는 목적의 데이터를 저장하는 것이고, 두 번째 파라미터는 교환 데이터이며, 세 번째 파라미터는 비교 데이터(첫 번째 파라미터와 비교)이다. 만약에 교환이 되돌아오는 데이터가 세 번째 파라미터와 같다면.
 
 
이렇게 하면 push와 pop에서 한꺼번에 완성할 수 있다.
여기에 push의 팝 동작을 붙여주세요.
procedure TVarQueue.pushQueue(pvData: PVarQueueBlock);
var
  lvTemp:PVarQueueBlock;
  lvPointer:Pointer;
begin
  while True do
  begin
     lvTemp := FTail;
     while lvTemp.next <> nil do lvTemp := lvTemp.next;
     if InterlockedCompareExchangePointer(Pointer(lvTemp.next), Pointer(pvData), nil) = nil then
     begin
       break;
     end;
  end;
  FTail := pvData;
  Inc(FCount);
end;
function TVarQueue.popQueue: PVarQueueBlock;
var
  lvTemp, lvRet:PVarQueueBlock;
  lvPointer:Pointer;
begin
  ///              FHead   
  ///      FHead                 
  ///

  while True do
  begin
    lvTemp := FHead;
    if (lvTemp = nil) or (lvTemp.next = nil) then
    begin        //      Pop   
      Result := nil;
      exit;
    end;
    if InterlockedCompareExchangePointer(Pointer(FHead), lvTemp.next, lvTemp) = lvTemp then
    begin
      break;
    end;
  end;
  Dec(FCount);
  lvRet := lvTemp.next;
  Result := lvRet;
  lvTemp.next := nil;
  Dispose(lvTemp);
  //    head.next
end;

 
나중에 DIOCP 프로젝트에 전체 코드를 업로드합니다.
만약 빈틈이 있으면 지적해 주십시오.환영합니다. 만약에 DIOCP 그룹 토론이
 
 

좋은 웹페이지 즐겨찾기