DELPHI高性能大容量SOCKET并发(五):锁和对象分离
来源:互联网 发布:超市必买清单知乎 编辑:程序博客网 时间:2024/05/17 04:32
锁和对象一起封装的危险
在多线程编写中,绝大多数编码风格喜欢把锁和要访问的对象封装在同一个对象,释放对象的时候也释放锁,这样会造成死锁。我们写一个测试例子,我们创建一个锁,把锁锁住,然后再创建一个线程,一直不停的等待锁返回,然后我们把锁释放,这时线程就死锁,代码如下:
定义接口:
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;在Form1创建的时候创建锁,并把锁锁住,创建一个线程等待锁返回: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;V1版下载地址:http://download.csdn.net/detail/sqldebug_fan/4510076,需要资源10分,有稳定性问题,可以作为研究稳定性用;
V2版下载地址:http://download.csdn.net/detail/sqldebug_fan/5560185,不需要资源分,解决了稳定性问题和提高性能;免责声明:此代码只是为了演示IOCP编程,仅用于学习和研究,切勿用于商业用途。水平有限,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com
- DELPHI高性能大容量SOCKET并发(五):锁和对象分离
- 高性能大容量SOCKET并发(五):锁和对象分离 .
- DELPHI高性能大容量SOCKET并发(八):断点续传
- DELPHI高性能大容量SOCKET并发(十):IOCP完成端口性能优化
- DELPHI高性能大容量SOCKET并发(一):IOCP完成端口例子介绍
- DELPHI高性能大容量SOCKET并发(二):IOCP完成端口控件封装
- DELPHI高性能大容量SOCKET并发(三):接收、发送、缓存
- DELPHI高性能大容量SOCKET并发(六):协议字符集
- DELPHI高性能大容量SOCKET并发(七):通讯协议
- DELPHI高性能大容量SOCKET并发(四):粘包、分包、解包
- DELPHI高性能大容量SOCKET并发(九):稳定性问题解决
- DELPHI高性能大容量SOCKET并发(四):粘包、分包、解包
- C#高性能大容量SOCKET并发(五):粘包、分包、解包
- C#高性能大容量SOCKET并发(五):粘包、分包、解包
- C#高性能大容量SOCKET并发(五):粘包、分包、解包
- Netty高性能大容量Socket并发
- C#高性能大容量SOCKET并发(九):断点续传
- DELPHI高性能大容量SOCKET并发:IOCP完成端口例子介绍
- VC编写的windows入口函数:WinMain(孙鑫视频所讲)
- 工作感悟
- Spring3开发实战 之 第二章:IoC/DI开发(1)
- SVN分支和合并的简单例子
- poj 3750 小孩报数问题
- DELPHI高性能大容量SOCKET并发(五):锁和对象分离
- 黑马程序员--强类型DataSet数据导入导出
- DELPHI高性能大容量SOCKET并发(六):协议字符集
- 给网页添加背景图片
- HDU 1864 01背包
- myeclipse使用心得———新建文件夹(把我找的网页资料集合在一起)
- 一个计算机爱好者的不完整回忆(四十)做过的一些“外挂”
- Spring3开发实战 之 第二章:IoC/DI开发(2)
- DELPHI高性能大容量SOCKET并发(七):通讯协议