高性能大容量SOCKET并发(五):锁和对象分离
锁和对象一起封装的危险
在多线程编写中,绝大多数编码风格喜欢把锁和要访问的对象封装在同一个对象,释放对象的时候也释放锁,这样会造成死锁。我们写一个测试例子,我们创建一个锁,把锁锁住,然后再创建一个线程,一直不停的等待锁返回,然后我们把锁释放,这时线程就死锁,代码如下:
定义接口:
{ 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;IOCPDemoSvr下载地址:http://download.csdn.net/detail/sqldebug_fan/4510076
免责声明:此代码只是为了演示IOCP编程,仅用于学习和研究,切勿用于商业用途。水平有限,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com