2012-08-30 29 views
4

我无法理解在代码中使用lock()语句的方式。我有几个静态集合像这样:何时使用并发锁定语句

private static Dictionary<string, User>() Users = new Dictionary<string, User>(); 

我不断地添加,删除,更新和读取此集合。我意识到,当我添加,删除或更新时,我应该锁定Users,但是当我从集合中读取时,是否必须锁定它?什么是正确的方式来做一些事情,如搜索一个密钥并返回字典中的User?我正在考虑创建一个新的Dictionary实例,然后将用户复制到该实例并从中读取,或者我可以直接从中读取它?

回答

4

这里最好的选择可能是去除锁,并使用ConcurrentDictionary<string, User>而不是Dictionary<string, User>

否则,您需要同步您的读取。您可以从多个线程中读取数据,但如果一位作者在读者阅读时正在写字典,则需要同步。 ReaderWriterLock(或ReaderWriterLockSlim)在这种情况下可以很好地工作,因为它们可以允许多个阅读器,但只能有一个作者。一个简单的lock也可以工作,但会比所需的更频繁地阻止。

+0

不是ReaderWriterLoc(Slim)对于像添加/删除/读取字典这样的简单操作的锁定时间的矫枉过正? –

+0

@DirkBonné它完全依赖 - 它通常是最合适的机制(尽管在.NET 4中,我只是使用ConcurrentDictionary)。如果你有很多读者,但偶尔会有重叠的作者,这会比锁好,因为锁会阻止并发读取。 –

2

如果您使用的是C# 4.0或更多,您可以使用ConcurentDictionary来处理所有这些东西。

如果你没有或者由于某种原因不能使用4.0,是的,你需要自己的ReadWriteContains锁定机制来实现,以模拟基本ACID原则,像

  • Consistensy
  • Isoltaion
  • 耐用性。

不要认为原子性在这种情况下有很多处理。

希望这会有所帮助。

+0

这只能保证了每个单独的操作出现的原子。如果你曾经执行过多种相互依赖的方法,你需要“锁定”。 – Servy

+0

@Servy:给我一点时间写东西:) – Tigran

+0

不要发布你的答案,直到你完成:) – Servy

3

但是当我从集合中读取时是否必须锁定它?

是的,如果在读取过程中另一个线程可能会修改字典。

什么是正确的方法来做一些事情,如搜索一个密钥并返回字典中的用户?

使用TryGetValue方法。

如果您使用.Net 4.0或更高版本,则可以使用线程安全的ConcurrentDictionary集合。

+0

如果您只读*,则无需锁定。如果你正在阅读,而其他人可能同时也可能不会同时书写,那么你需要锁定。 – Servy

+1

@Servy - 谢谢你指出,我应该更具体;答案已更新。 – dugas