C# 添加或更新时是否锁定ConcurrentDictionary?
我使用C# 添加或更新时是否锁定ConcurrentDictionary?,c#,.net,thread-safety,concurrentdictionary,C#,.net,Thread Safety,Concurrentdictionary,我使用ConcurrentDictionAnry跨多个线程访问一些数据 我读到(向下滚动)锁中没有执行方法AddOrUpdate,因此可能会危及线程安全 我的代码如下: //keys and bar are not the concern here ConcurrentDictioanry<string, HashSet<string>> foo = new ...; foreach(var key in keys) { foo.AddOrUpdate(key,
ConcurrentDictionAnry
跨多个线程访问一些数据
我读到(向下滚动)锁中没有执行方法AddOrUpdate
,因此可能会危及线程安全
我的代码如下:
//keys and bar are not the concern here
ConcurrentDictioanry<string, HashSet<string>> foo = new ...;
foreach(var key in keys) {
foo.AddOrUpdate(key, new HashSet<string> { bar }, (key, val) => {
val.Add(bar);
return val;
});
}
//这里不关心键和条
ConcurrentDictionAnry foo=新。。。;
foreach(var键入键){
AddOrUpdate(key,new HashSet{bar},(key,val)=>{
val.Add(bar);
返回val;
});
}
我是否应该将
AddOrUpdate
调用包含在lock
语句中,以确保一切都是线程安全的?在AddOrUpdate
期间单独锁定不会有帮助-您仍然必须在每次读取集合时锁定
如果要将此集合视为线程安全的,则确实需要这些值也是线程安全的。理想情况下,您需要一个ConcurrentSet
。现在,框架中不存在这一点(除非我遗漏了什么),但是您可以创建自己的ConcurrentSet
,它使用concurrentdirectionary
(或者您喜欢的任何TValue
)作为其底层数据结构。基本上,您会忽略字典中的值,而只将键的存在视为重要部分
您不需要实现ISet中的所有内容,只需要实际需要的位
然后,您可以在应用程序代码中创建一个
ConcurrentDictionary
,这样您就不需要锁定了。这篇文章指出,add委托没有在字典的锁中执行,您得到的元素可能不是add委托在该线程中创建的元素。这不是线程安全问题;字典的状态将是一致的,所有调用方都将获得相同的实例,即使为每个调用方创建了不同的实例(并且除一个实例外,所有调用方都将被删除)。您需要修复此代码,它会产生大量垃圾。即使不需要任何哈希集,也可以创建新的哈希集。使用另一个重载,即接受valueFactory委托的重载。因此,哈希集仅在密钥尚未出现在字典中时创建
如果多个线程同时尝试添加键的相同值,但该值不存在,则可能会多次调用valueFactory。几率很低,但不是零。将只使用其中一个哈希集。这不是问题,创建HashSet没有可能导致线程问题的副作用,额外的副本只是被垃圾收集。似乎更好的答案是在传递委托的方法上使用Lazy
另外还有一篇关于延迟加载add委托的好文章 如果通过API访问(读写)我的
ConcurrentDictionary
实例会怎么样?所以客户端代码实际上不会注意到有一个ConcurrentDictionary
,那么我可以安全地在API的公共方法中进行锁定,对吗?我只是想了解这里的情况…@保罗:是的,你可以确保每次访问任何东西时都能锁定。。。但是你认为ConcurrentDictionary真正为你买了什么?请看我的问题,正是关于这个问题:谢谢,通过使用另一个重载修复了这个问题。