C#不可变哈希集锁定

C#不可变哈希集锁定,c#,c#-7.0,C#,C# 7.0,假设服务器存储一组不可变的连接数据 ImmutableHashSet<ConnectionData> connections = new ... 我的问题是,在上面只对HashSet执行一个操作(Add/Remove)的调用中,我应该锁定连接吗?或者ImmutableHashSet操作是线程安全的?方法调用Add和Remove返回一个全新的ImmutableHashSet。因此,当类型为时,您需要使用锁定来处理同时发生对Add或Remove的多个调用的情况。否则,如果两个Add调用

假设服务器存储一组不可变的连接数据

ImmutableHashSet<ConnectionData> connections = new ...

我的问题是,在上面只对HashSet执行一个操作(Add/Remove)的调用中,我应该锁定连接吗?或者ImmutableHashSet操作是线程安全的?

方法调用
Add
Remove
返回一个全新的
ImmutableHashSet
。因此,当类型为时,您需要使用锁定来处理同时发生对
Add
Remove
的多个调用的情况。否则,如果两个
Add
调用同时发生(例如),则会出现典型的竞争条件

因此,您需要使用锁定对象:

private object lockObject = new lockObject();
然后在分配给
连接的每个代码块周围使用
lock(lockObject)
(例如,您的
添加
删除
调用)


另请参见@Flydog57在上述评论中提供的精彩链接。

您将值直接分配回集合的模式不是线程安全的。但是,在使用不可变集合时,通常不希望
锁定
。这些集合的主要特性之一是无锁操作,这通常会显著提高性能。相反,请使用
ImmutableInterlocked
类:

ImmutableHashSet<ConnectionData> connections;

ImmutableInterlocked.Update(ref connections,
                            (collection, item) => collection.Add(item),
                            connectionData);

ImmutableInterlocked.Update(ref connections,
                            (collection, item) => collection.Remove(item),
                            connectionData);
ImmutableHashSet连接;
ImmutableInterlocated.Update(参考连接,
(集合,项目)=>集合。添加(项目),
连接数据);
ImmutableInterlocated.Update(参考连接,
(收集,项目)=>收集。删除(项目),
连接数据);

您在
连接上执行两个操作
变量。ImmutableHashSet操作是否线程安全?阅读文档-但这并不是你应该阅读的@EricLippert 2007年末关于不变性的博客系列的全部故事,它从这里开始:。如果集合是不可变的,则您所引用的集合始终具有内部完整性,并且永远不会更改。但是,另一个线程上的参与者引用的不一定是同一个线程。“在使用不可变集合时,通常不希望锁定”-为什么?@kofifus lock-free更便宜,因为在争用较低的情况下,它平均会做更少的工作。在高争用期间,无锁仍会更快,但速度会更低,而且它会倾向于分配更多。幸运的是,这些分配都将在gen-0 GC中,这是非常便宜的。也就是说,如果您具有高争用性,那么不可变集合就不适合于锁定:它们不是为高写争用性而设计的。在这种情况下,您可能需要使用类似于
ConcurrentDictionary
的工具,它支持实际的并发使用。很有趣,谢谢您的解释。。关于ImmutableInterlocated是如何工作的,有什么好的解释/讨论吗?(似乎每个方法的microsoft文档只有1-2行)@kofifus您可以通过下载dotPeek并反编译
ImmutableInterlocated.Update
来验证该方法的功能。总之,它在一个循环中调用
Interlocked.compareeexchange
,直到成功。因此,如果我正确理解这一点,那么在本例中,更新返回的bool将表示hashset方法的结果,就像如果返回true,则表示添加/删除了值,如果返回false,则表示在“old”之间没有发现任何差异和新的集合(例如,在我们有机会之前添加/删除了另一个线程,或者该值已经存在/从未存在过)。。。所以对于使用锁的HashSet上的Add/Remove方法,您的意图和目的是什么?
ImmutableHashSet<ConnectionData> connections;

ImmutableInterlocked.Update(ref connections,
                            (collection, item) => collection.Add(item),
                            connectionData);

ImmutableInterlocked.Update(ref connections,
                            (collection, item) => collection.Remove(item),
                            connectionData);