何时在并发中使用锁语句

4

我有些困难理解如何在我的代码中使用lock()语句。我有一些静态集合,如下所示:

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

我不断地向这个集合中添加、删除、更新和读取内容。我意识到当我添加、删除或更新时,应该锁定 Users,但当我从集合中读取内容时,我需要锁定吗?在类似于搜索键并返回字典中的User的操作中,什么是正确的方法?我考虑创建一个新的Dictionary实例,然后将用户复制到其中并从中读取,或者我可以直接从原始集合中读取?
4个回答

4
这里最好的选择可能是删除锁定,使用ConcurrentDictionary<string, User>代替Dictionary<string, User>

否则,你也需要同步你的读取操作。你可以从多个线程中读取,但如果写入者在读取者读取时写入字典,就需要同步。在这种情况下,ReaderWriterLock(或ReaderWriterLockSlim)非常适合,因为它们可以允许多个读取者,但只有一个写入者。一个简单的lock也可以工作,但会比所需的更频繁地阻塞。

使用ReaderWriterLoc(Slim)对于像添加/删除/读取字典这样简单的操作来说,是否有点过度锁定时间了呢? - Dirk Bonné
@DirkBonné 这完全取决于情况 - 在许多情况下,这是最合适的机制(尽管在.NET 4中,我会直接使用ConcurrentDictionary)。如果你有很多读者,但偶尔会有重叠的写入操作,使用这种机制比使用锁更高效,因为锁会阻塞并发读取操作。 - Reed Copsey

3

但是当我从集合中读取时,我需要锁定它吗?

是的,如果在读取期间可能有另一个线程修改字典。

如何正确地搜索键并返回字典中的用户?

使用TryGetValue方法。

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


如果你只是读取,那么就不需要锁定。如果你正在读取,而可能或可能没有其他人同时在写入,那么你需要锁定。 - Servy
1
@Servy - 感谢您指出这一点,我应该更加具体; 答案已更新。 - dugas

2
如果您使用的是 C# 4.0 或更高版本,您可以利用 ConcurrentDictionary 来处理所有这些内容。
如果由于某种原因您没有或无法使用 4.0 版本,则需要自己实现在 Read、Write 和 Contains 上的锁定机制,以模拟基本的 ACID 原则,如一致性、隔离性和持久性。
不要认为在这种情况下原子性有很大的作用。
希望能帮到您。

这仅确保每个单独的操作都呈现为原子操作。如果您正在执行相互依赖的多个方法,则需要“锁定”。 - Servy
@Servy:给我一点时间写点东西 :) - Tigran
原子性是指从外部观察,所有在ConcurrentDictionary上调用的方法都是原子的(如果它们采用函数Func,那么这并不完全正确,但如果它们是功能性的Func - 并且它们有这个名称的原因 - 那么它们被调用多次的情况可能不会被观察到)。 - Jon Hanna

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接