3

假设我有这个简单的代码:(简化)

哪里MyConCurrentDictionary是静态的ConcurrentDictionary<string, string> (位于不同的类中)。

/*1*/   public void Send(string Message, string UserName)
/*2*/   {            
/*3*/       string ConnectionId;
/*4*/       if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId))
/*5*/       {
/*6*/       //...   
/*7*/           DB.InsertMessage( Message, ConnectionId);
/*8*/           LOG.LogMessage  ( Message, ConnectionId);
/*9*/       //...
/*10*/       }
/*11*/       else ...
/*12*/   }

此方法从许多实例运行。(如果你愿意,signalR 集线器)

我需要插入DB/log user/connectionID存在时。

好的,所以#4当多线程访问时行是线程安全的ConcurrentDictionary

但是还有另一种方法是 RemoveUser - 从字典中删除用户:

 public void RemoveUser (string userName)
        {
           string removed;
           if ( MyConCurrentDictionary.TryRemove(userName,out removed ))
              Clients.All.removeClientfromChat(userName);
        }

但是上下文可能会出现在行#5中,这将执行RemoveUser 并从 ConcurrentDictionary 中删除用户名。

所以为了解决这个问题 - 代码将是这样的:

lock(locker)
{
  if (MyConCurrentDictionary.TryGetValue(UserName,out ConnectionId))
   {
    //...
   }

}

这完全违背了我的目的 ConcurrentDictionary

问题

在多线程环境中做这样的事情的正确方法是什么 - 仍然有 ConcurrentDictionary 的好处?

nb ,是的 ConcurrentDictionary 仅对字典内的操作是线程安全的。但我想说的是,在特定情况下,我失去了 ConcurrentDictionary 的好处,因为我仍然需要使用锁。(我可能错了)。

4

2 回答 2

3

根据您所写的内容和我到目前为止的理解: ConcurrentDictionary 不是合适的选择!

编写一个包装普通 Dictionary 的类,并通过ReaderWriterLockSlim. 这比普通锁要快得多。您也可以进行多次读取,但一次只能进行一次写入操作。

private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

public void DoRead(string xyz)
{
    try
    {
        _lock.EnterReadLock();
        // whatever
    }
    finally
    {
        _lock.ExitReadLock();
    }
}

public void DoWrite(string xyz)
{
    try
    {
        _lock.EnterWriteLock();
        // whatever
    }
    finally
    {
        _lock.ExitWriteLock();
    }
}
于 2014-05-19T09:07:14.627 回答
1

它看起来像设计问题。

你有ConcurentDictionary,但你没有原子地使用它,有一个由几个命令组成的操作,所以你必须使用lock(或其他同步)。

最简单的解决方案是允许LOG拥有已删除用户 ID 的消息,换句话说,在处理消息时处理此 cas(使用TryGetValuefrom ) 。MyConcurentDictionaryLOG

我还可以考虑拥有 2 个集合:一个具有有效的用户 ID,另一个具有删除 user的集合。当您要添加到 时LOG,会检查两个集合。当您想删除用户时,您将该用户添加到已删除的用户集合中,并在一段时间后将该用户从有效集合中删除(某个时间 = 1 秒或其他时间)。

于 2014-05-19T08:17:41.873 回答