5

在访问集合的简单属性时,锁定有什么好处或坏处,特别是.Count?(这是可取的,不可取的,还是一点也不重要?)(当然我需要在任何写入或读取时锁定它)

private Dictionary<string, bool> database = new Dictionary<string, bool>();
private object databaseLock = new object();
public int Count
{
    get
    {
        lock (databaseLock)
        {
            return database.Count;
        }
    }
}

我个人认为这可能是可取的,只是为了打破需要锁定访问字典的约定,而不是出于任何实际原因[*]。此外,在您访问的任何属性中,可能会有比预期更多的操作。

[*] 知道在 C# 中的(大多数)集合中,Count它是一个由它维护的整数,因此应该始终是原子操作

4

3 回答 3

5

是的,在并发写入的情况下需要锁定,因为文档Dictionary不保证这是安全的。你不能假设任何关于它的内部结构。

此规则的例外情况需要极端情况。

TL;DR:仅依靠记录在案的行为,否则您最终会发现自己处于受伤的世界中。

于 2012-12-07T21:30:18.157 回答
2

这种代码严重属于“伤害”类别。也是非常严重的伤害。锁只是不能保护任何东西。在属性 getter 退出锁定后的纳秒内,没有什么可以阻止线程向字典添加或删除项目。这使得 Count 值只返回垃圾。当您获得值时,您不知道字典中有多少项。到目前为止,这个错误最有害的方面是它通常是正确的。

此代码将保证您创建了线程竞赛,这是迄今为止诊断的最糟糕的错误类型。

于 2012-12-07T21:43:03.663 回答
1

编辑:正如 usr 在他的回答 中指出的那样,这Dictonary.Count不是线程安全的。文档说:

通过集合枚举本质上不是线程安全的过程。在枚举与写访问竞争的极少数情况下,必须在整个枚举期间锁定集合。

意味着需要同步。请注意,可能正在修改集合的任何其他代码都需要使用相同的锁。这很容易出错,如果 Dictionary 被多个线程使用,请考虑 改用ConcurrentDictionary

于 2012-12-07T21:31:09.360 回答