C# 线程:锁定通用字典

C# 线程:锁定通用字典,c#,multithreading,C#,Multithreading,我在多线程应用程序中有一个通用字典;为了实现锁,我创建了一个属性 static object myLock=new object(); Dictionary<key,SomeRef> dict=new Dictionary<key,SomeRef>(); public Dictionary<key,SomeRef> MyDict{ get{ lock(myLock){ return dict; }

我在多线程应用程序中有一个通用字典;为了实现锁,我创建了一个属性

static object myLock=new object();
Dictionary<key,SomeRef> dict=new Dictionary<key,SomeRef>();

public Dictionary<key,SomeRef> MyDict{
      get{
        lock(myLock){
        return dict;
        }
     }
 }
或代码2

var result=MyDict.Values;
foreach(var item in result){
//read value into some other variable
}
因此,当我运行代码1或2时,同时如果其他线程尝试在字典上执行写操作,如..清除dict或添加新项。那么,这个解决方案是否使用属性是线程安全的呢。 如果没有,那么还有其他方法吗


当我说写操作时,它可以通过属性chek key exist引用dict,如果不创建键并赋值,也可以不引用dict。因此,如果我不在属性中使用setter,这将不是线程安全的

锁只会锁定对字典内部dict实例的引用。当用户尝试添加到词典或从词典中读取时,它不会锁定

如果您需要提供线程安全访问,我建议将字典保持私有,并制定自己的方法来获取/设置/添加字典中的值。通过这种方式,您可以按需要的粒度将锁放在适当的位置进行保护

这将看起来像这样:

public bool TryGetValue(key thekey, out SomeRef result)
{
    lock(myLock) { return this.dict.TryGetValue(thekey, out result); }
}
public void Add(key thekey, SomeRef value)
{
    lock(myLock) { this.dict.Add(thekey, value) }
}
// etc for each method you need to implement...

这里的想法是,您的客户机直接使用您的类,而您的类处理同步。如果希望它们在foreach语句等值上迭代,则可以决定是将值复制到列表中并返回该列表,还是直接提供枚举器IEnumerator GetValues等。

否,这将不是线程安全的

锁只会锁定对字典内部dict实例的引用。当用户尝试添加到词典或从词典中读取时,它不会锁定

如果您需要提供线程安全访问,我建议将字典保持私有,并制定自己的方法来获取/设置/添加字典中的值。通过这种方式,您可以按需要的粒度将锁放在适当的位置进行保护

这将看起来像这样:

public bool TryGetValue(key thekey, out SomeRef result)
{
    lock(myLock) { return this.dict.TryGetValue(thekey, out result); }
}
public void Add(key thekey, SomeRef value)
{
    lock(myLock) { this.dict.Add(thekey, value) }
}
// etc for each method you need to implement...

这里的想法是,您的客户机直接使用您的类,而您的类处理同步。如果您希望它们在foreach语句等值上进行迭代,则可以决定是将值复制到列表中并返回该列表,还是直接提供枚举器IEnumerator GetValues等。

否,这将不安全,因为唯一锁定的代码是检索代码。你需要做的是

lock(MyDict)
{
   if(MyDict.TryGetValue()...
}


基本思想是将工作代码封装在锁块中。

不,这不安全,因为唯一被锁定的代码是检索代码。你需要做的是

lock(MyDict)
{
   if(MyDict.TryGetValue()...
}


基本思想是将工作代码封装在锁块中。

实现不能保证线程安全。为了线程安全,并发读/写操作都必须受到锁的保护。通过分发对内部字典的引用,您很难控制谁访问资源,因此您无法保证调用者将使用相同的锁


一个好方法是确保您试图同步访问的任何资源都完全封装在您的类型中。这将使理解和解释该类型的线程安全性变得更加容易。

实现不能保证线程安全。为了线程安全,并发读/写操作都必须受到锁的保护。通过分发对内部字典的引用,您很难控制谁访问资源,因此您无法保证调用者将使用相同的锁

一个好方法是确保您试图同步访问的任何资源都完全封装在您的类型中。这将更容易理解和解释该类型的线程安全性。

这是一种使用ReaderWriterLockSlim和确定性终结来保持和释放锁的方法。


这是一种使用ReaderWriterLockSlim和确定性终结来保持和释放锁的方法。

您好,谢谢。lockMyDict{ifMyDict.TryGetValue…}和lockMyLock{ifMyDict.TryGetValue…}之间的区别是什么唯一的区别是lock对象。锁定字典或其他特定于资源的对象只是惯例。只要你使用相同的同步对象,你就可以了。嗨,亚当,谢谢。lockMyDict{ifMyDict.TryGetValue…}和lockMyLock{ifMyDict.TryGetValue…}之间的区别是什么唯一的区别是lock对象。锁定字典或其他特定于资源的对象只是惯例。只要使用相同的同步对象,就可以了。