2

假设在 C# 中,您有一个Dictionary<K, V>对象,多个线程正在访问和更改。您希望某些操作是线程安全的。

因此,您需要一个互斥锁。在 C# 中,使用互斥锁的标准方法是:

lock (someSharedObject)
{
   // Mutual exclusion zone here.
   myDictionary.Add(1, "hello");
}

问题是,您仅依靠文档来防止未来的程序员绕过互斥锁直接访问字典:

myDictionary.Add(1, "hello");

我希望编译器阻止未来的程序员使用不受保护的字典。

我看到两种一般可能性:

  1. 创建一个相似的字典(例如,LockedDictionary),它确保锁定其成员方法,但在其他方面都像字典一样。
  2. 创建一个保护对 的访问的类,因此调用者在不通过保护的情况下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。我错过了任何优点和缺点吗?有没有更好的方法来保护对我的字典的访问,同时最大限度地减少误用的风险?同样,我的要求是健忘或粗心的程序员不能跳过锁定阶段。我的愿望是它是惯用的、方便的和灵活的。

4

1 回答 1

3

你考虑过ConcurrentDictionary<TKey, TValue>吗?它和其他并发集合是在 .NET 4.0 中引入的。

表示可由多个线程同时访问的键/值对的线程安全集合。

于 2013-04-04T20:23:11.463 回答