数据结构的C#中惯用的保证互斥?

数据结构的C#中惯用的保证互斥?,c#,locking,C#,Locking,假设在C#中有一个字典对象,多个线程正在访问和更改该对象。您希望某些操作是线程安全的 所以你需要一个互斥。在C#中,使用互斥的标准方式是: lock (someSharedObject) { // Mutual exclusion zone here. myDictionary.Add(1, "hello"); } 问题是,您仅仅依靠文档来阻止未来的程序员绕过互斥锁直接访问字典: myDictionary.Add(1, "hello"); 我希望编译器能够阻止未来的程序员使用未受

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

所以你需要一个互斥。在C#中,使用互斥的标准方式是:

lock (someSharedObject)
{
   // Mutual exclusion zone here.
   myDictionary.Add(1, "hello");
}
问题是,您仅仅依靠文档来阻止未来的程序员绕过互斥锁直接访问字典:

myDictionary.Add(1, "hello");
我希望编译器能够阻止未来的程序员使用未受保护的字典

我认为有两种可能性:

  • 创建一个外观相似的字典(比如,
    LockedDictionary
    ),它确保锁定其成员方法,但在其他方面与字典类似
  • 创建一个保护对
    字典
    访问的类,以便调用者不通过保护就无法访问
    字典
  • 这些满足了人们的期望,即现在没有人可以在没有保护的情况下使用字典,至少是无意中。我想讨论两者的利弊,然后请你同意或不同意我的观点,并提出一个我可能忽略的解决方案

    LockedDictionary
    的优点在于它对其他人来说是直观的。它还允许细粒度地控制哪些方法需要锁定以及锁定的程度。缺点是它不完全是一个
    字典
    ,因此不能将此对象传递给期望接收
    字典
    的函数。(尽管您可以通过实现
    IDictionary
    来接近这一点)

    继续讨论第二个问题。guard类的优点在于,您可以实现
    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
    }
    
    类字典fortress{
    词典;
    对象锁定对象;
    无效锁(){
    Monitor.Enter(锁定对象);
    返回字典Guard(lockobject,realDict);
    }
    }
    类字典Guard:IDisposable{
    公共词典词典{
    获取{return realDict;}
    }
    公共空间处置(){
    监视器。退出(锁定对象);
    }
    }
    //在某个班级
    DictionaryFortress dict=新DictionaryFortress();//早期
    //在函数中,当我们需要访问字典内容时。。。
    使用(DictionaryGuard guard=dict.Lock()){
    Dictionary actualDict=guard.Dict;
    //现在,您可以在任何地方传递ActualAct;没有人必须知道它已锁定
    }
    
    当然,好处是我们可以访问原始字典,因此我们不受如何使用它以及在哪里传递它的限制。缺点是使用它会带来更多的开销。用户还可以在可用时保存对
    guard.Dict
    的引用,然后在释放DictionaryGuard后使用它

    我倾向于#2。我是否错过了任何有利和不利因素?有没有更好的方法来保护对我的字典的访问,同时最大限度地减少误用的风险?同样,我的要求是健忘或粗心的程序员不能跳过锁定阶段。我的愿望是它既地道、方便又灵活。

    你考虑过吗?它和另一个是在.NET4.0中引入的

    表示线程安全的键/值对集合,可以 由多个线程并发访问


    您是否考虑过?或其他线程安全集合的ConcurrentBag、ConcurrentQueue和ConcurrentStack。再发明轮子也没有意义了…谢谢你。虽然我知道我肯定是在重新发明轮子,但我忘记了这些东西的存在。你能把这个作为建议的答案吗?完成了。它是在.NET4.0中引入的。