假设在 C# 中,您有一个Dictionary<K, V>
对象,多个线程正在访问和更改。您希望某些操作是线程安全的。
因此,您需要一个互斥锁。在 C# 中,使用互斥锁的标准方法是:
lock (someSharedObject)
{
// Mutual exclusion zone here.
myDictionary.Add(1, "hello");
}
问题是,您仅依靠文档来防止未来的程序员绕过互斥锁直接访问字典:
myDictionary.Add(1, "hello");
我希望编译器阻止未来的程序员使用不受保护的字典。
我看到两种一般可能性:
- 创建一个相似的字典(例如,
LockedDictionary
),它确保锁定其成员方法,但在其他方面都像字典一样。 - 创建一个保护对 的访问的类,因此调用者在不通过保护的情况下
Dictionary
无法到达。Dictionary
这些满足了人们想要的特性,即现在没有人可以不受保护地使用字典,至少是偶然的。我想讨论两者的优缺点,然后请您同意或不同意我的观点,并提出我可能忽略的解决方案。
好处LockedDictionary
是对其他人来说很直观。它还允许对哪些方法需要锁定以及锁定程度进行细粒度控制。缺点是它不完全是 a Dictionary
,因此您不能将此对象传递给期望接收 a 的函数Dictionary
。(尽管您可以通过实施来接近IDictionary
。)
继续#2。守卫类的好处是你可以IDisposable
像这样实现和使用它:
class DictionaryFortress {
Dictionary<K, V> realDict;
Object lockobject;
void Lock() {
Monitor.Enter(lockobject);
return DictionaryGuard(lockobject, realDict);
}
}
class DictionaryGuard : IDisposable {
public Dictionary<K, V> Dict {
get { return realDict; }
}
public void Dispose() {
Monitor.Exit(lockobject);
}
}
// in some class
DictionaryFortress dict = new DictionaryFortress(); // early on
// in a function, when we need to access dictionary contents...
using (DictionaryGuard guard = dict.Lock()) {
Dictionary<K, V> actualDict = guard.Dict;
// now you can pass actualDict anywhere; no one has to know that it's locked
}
当然,好处是我们可以访问原始字典,因此我们不受限制如何使用它以及可以在哪里传递它。缺点是使用它的开销更大。用户也可以在引用guard.Dict
可用时保存它,然后在处理 DictionaryGuard 后使用它。
我倾向于#2。我错过了任何优点和缺点吗?有没有更好的方法来保护对我的字典的访问,同时最大限度地减少误用的风险?同样,我的要求是健忘或粗心的程序员不能跳过锁定阶段。我的愿望是它是惯用的、方便的和灵活的。