[セットトップ]DELPHI高性能大容量SOCKET同時(5):ロックとオブジェクト分離

5612 ワード

ロックがオブジェクトと一緒にカプセル化される危険
マルチスレッド作成では、ほとんどの符号化スタイルは、ロックとアクセスするオブジェクトを同じオブジェクトにカプセル化するのが好きで、オブジェクトを解放するときもロックを解放します.これにより、デッドロックが発生します.テスト例を書いて、ロックを作成して、ロックをロックして、それからスレッドを作成して、ずっとロックが戻ってくるのを待っていて、それからロックを解放して、この時スレッドはデッドロックして、コードは以下の通りです.
インタフェースの定義:
type
  TLockObject = class;
  TLockTestThread = class;
  TForm1 = class(TForm)
    btn1: TButton;
    mmoLockThreadTest: TMemo;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FLockTestThread: TLockTestThread;
    FLockObject: TLockObject;
  public
    { Public declarations }
  end;

  TLockTestThread = class(TThread)
  private
    FLockObject: TLockObject;
  public
    procedure Execute; override;
    procedure AddLockLog;
    property LockObject: TLockObject read FLockObject write FLockObject;
  end;

  TLockObject = class(TObject)
  private
    FLock: TCriticalSection;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    procedure Lock;
    procedure UnLock;
  end;

var
  Form1: TForm1;
Form 1の作成時にロックを作成し、ロックをロックし、スレッド待機ロックの戻りを作成します.
procedure TForm1.FormCreate(Sender: TObject);
begin
  FLockObject := TLockObject.Create;
  FLockObject.Lock;
  FLockTestThread := TLockTestThread.Create(True);
  FLockTestThread.LockObject := FLockObject;
  FLockTestThread.FreeOnTerminate := True;
  FLockTestThread.Resume;
end;
スレッドの実行方法は、ロックが戻るのを待ってログを書きます.フォームの作成時にロックがロックされているため、スレッドは待機します.
procedure TLockTestThread.AddLockLog;
begin
  Form1.mmoLockThreadTest.Lines.Add('Lock')
end;

procedure TLockTestThread.Execute;
begin
  inherited;
  while not Terminated do
  begin
    FLockObject.Lock;
    Synchronize(AddLockLog);
  end;
end;
この時点でスレッドはずっと待っています.FLockObjectを解放すると、スレッドもずっと待っていて、デッドロックになります.
procedure TForm1.btn1Click(Sender: TObject);
begin
  FLockObject.Lock;
  FLockObject.Free;
  FLockObject := nil;
end;

ロックとオブジェクトの分離
上記の基礎があれば、ロックとオブジェクトを分離する必要があります.IOCPDemoSvrの例コードでは、TSocketHandleは構造体でロックとオブジェクトを管理しています.ロックは作成後、TSocketHandleが解放されてから解放されます.主なコードはTSocketHandlesクラスで、定義ユニットです.
  {*  Socket  *}
  TSocketHandles = class(TObject)
  private
    {*   *}
    FList: TList;
    {*   *}
    FIdleList: TList;
    {*   *}
    FLock: TCriticalSection;
    {*   *}
    function GetItems(const AIndex: Integer): PClientSocket;
    {*   *}
    function GetCount: Integer;
    {*   *}
    procedure Clear;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    {*   *}
    procedure Lock;
    {*   *}
    procedure UnLock;
    {*   *}
    function Add(ASocketHandle: TSocketHandle): Integer;
    {*   *}
    procedure Delete(const AIndex: Integer); overload;
    procedure Delete(ASocketHandle: TSocketHandle); overload;
    property Items[const AIndex: Integer]: PClientSocket read GetItems; default;
    property Count: Integer read GetCount;
  end;
実装ユニット:
{ TSocketHandles }

constructor TSocketHandles.Create;
begin
  FList := TList.Create;
  FIdleList := TList.Create;
  FLock := TCriticalSection.Create;
end;

destructor TSocketHandles.Destroy;
begin
  Clear;
  FList.Free;
  FIdleList.Free;
  FLock.Free;
  inherited;
end;

function TSocketHandles.GetItems(const AIndex: Integer): PClientSocket;
begin
  Result := FList[AIndex];
end;

function TSocketHandles.GetCount: Integer;
begin
  Result := FList.Count;
end;

procedure TSocketHandles.Clear;
var
  i: Integer;
  ClientSocket: PClientSocket;
begin
  for i := 0 to Count - 1 do
  begin
    ClientSocket := Items[i];
    ClientSocket.Lock.Free;
    ClientSocket.SocketHandle.Free;
    Dispose(ClientSocket);
  end;
  FList.Clear;
  for i := 0 to FIdleList.Count - 1 do
  begin
    ClientSocket := FIdleList[i];
    ClientSocket.Lock.Free; // 
    Dispose(ClientSocket);
  end;
  FIdleList.Clear;
end;

procedure TSocketHandles.Lock;
begin
  FLock.Enter;
end;

procedure TSocketHandles.UnLock;
begin
  FLock.Leave;
end;

function TSocketHandles.Add(ASocketHandle: TSocketHandle): Integer;
var
  ClientSocket: PClientSocket;
begin
  if FIdleList.Count > 0 then // 
  begin
    ClientSocket := FIdleList[0];
    FIdleList.Delete(0);
  end
  else // 
  begin
    New(ClientSocket);
    ClientSocket.Lock := TCriticalSection.Create;
  end;
  ClientSocket.SocketHandle := ASocketHandle;
  ASocketHandle.FLock := ClientSocket.Lock;
  Result := FList.Add(ClientSocket);
end;

procedure TSocketHandles.Delete(const AIndex: Integer);
var
  ClientSocket: PClientSocket;
begin
  ClientSocket := FList[AIndex];
  ClientSocket.Lock.Enter;
  try
    ClientSocket.SocketHandle.Free;
    ClientSocket.SocketHandle := nil;
  finally
    ClientSocket.Lock.Leave;
  end;
  FList.Delete(AIndex);
  if FIdleList.Count > MAX_IDLELOCK then // , 
    Dispose(ClientSocket)
  else
    FIdleList.Add(ClientSocket);
end;

procedure TSocketHandles.Delete(ASocketHandle: TSocketHandle);
var
  i, iIndex: Integer;
begin
  iIndex := -1;
  for i := 0 to Count - 1 do
  begin
    if Items[i].SocketHandle = ASocketHandle then
    begin
      iIndex := i;
      Break;
    end;
  end;
  if iIndex <> -1 then
  begin
    Delete(iIndex);
  end;
end;

V 1版ダウンロードアドレス:http://download.csdn.net/detail/sqldebug_fan/4510076資源10分が必要で、安定性の問題があり、安定性を研究するために使用することができる.V 2版ダウンロードアドレス:http://download.csdn.net/detail/sqldebug_fan/5560185資源分を必要とせず、安定性の問題を解決し、性能を高めた.免責声明:このコードはIOCPプログラミングを実証するために使用され、学習と研究にのみ使用され、ビジネス用途には使用されません.レベルが限られていて、間違いは避けられないので、指摘と指導を歓迎します.メールアドレス:[email protected]