首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi -是TDictionary线程安全的

Delphi -是TDictionary线程安全的
EN

Stack Overflow用户
提问于 2014-12-17 01:41:47
回答 2查看 3.3K关注 0票数 4

我的想法是使用TDictionary来管理IdTCPServer上的客户端连接。下面是一个简单的示例代码(未经过测试),用于理解目的:

代码语言:javascript
复制
var
  Dic: TDictionary<string, TIdContext>;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  Dic := TDictionary<string, TIdContext>.Create;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  Dic.Free;
end;

procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
  Hostname: string;
begin
  Hostname := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
  if not Dic.ContainsKey(Hostname) then Dic.Add(Hostname, AContext);
end;

procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
  Hostname: string;
begin
  Hostname := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
  if Dic.ContainsKey(Hostname) then
  begin
    Dic[Hostname].Free;
    Dic.Remove(Hostname);
  end;
end;

这个代码线程安全吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-17 03:12:24

一句话:No

如果您检查TDictionary的来源,您应该很快意识到在实现本身中没有提供线程安全的规定。即使是这样,通过对Dic实例进行离散调用,您也可以处理潜在的争用条件:

代码语言:javascript
复制
  if Dic.ContainsKey(Hostname) then
  begin

    // In theory the Hostname key may be removed by another thread before you 
    //  get a chance to do this : ...

    Dic[Hostname].Free;
    Dic.Remove(Hostname);
  end;

您需要自己使用Dic线程安全,幸运的是,在这种示例中,使用对象本身上的监视器很容易实现这一点:

代码语言:javascript
复制
MonitorEnter(Dic);
try
  if not Dic.ContainsKey(Hostname) then 
    Dic.Add(Hostname, AContext);

finally
  MonitorExit(Dic);
end;


// ....


MonitorEnter(Dic);
try
  if Dic.ContainsKey(Hostname) then
  begin
    Dic[Hostname].Free;
    Dic.Remove(Hostname);
  end;

finally
  MonitorExit(Dic);
end;

如果您不熟悉Delphi中的监视器,那么简单地说,您可以将监视器看作是每个TObject后裔支持的随时使用的关键部分(在Delphi的旧版本中,它不支持这些监视器,您可以通过一个明确的关键部分实现相同的目标)。

票数 7
EN

Stack Overflow用户

发布于 2014-12-17 08:13:17

要回答您的具体问题-不,TDictionary不是线程安全的,所以您必须保护对它的访问。

您的代码没有处理多个客户端在代理/路由器后面连接到同一台服务器的可能性。它们都具有相同的PeerIPHostName值。这些值本身不够独特,无法识别客户端。您需要创建自己的唯一标识符,例如,让客户端以用户名登录到服务器,然后将其用作字典键。

最后,不要释放TIdContext对象!它们属于TIdTCPServer,并将在OnDisconnect事件处理程序退出后自动释放。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27517063

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档