C#List的线程安全性<;T>;给读者
我计划在静态构造函数中创建一次列表,然后让该类的多个实例在不进行任何锁定的情况下并发地读取(并枚举) 本文 MS将螺纹安全问题描述如下: 公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 任何实例成员都不是 保证线程安全 一个列表可以支持多个读卡器 同时,只要 集合未被修改。 在集合中枚举是不正确的 本质上不是线程安全的 程序在罕见的情况下 枚举与一个或多个 写访问,这是确保 螺纹的安全性在于锁紧螺纹 在整个过程中收集 枚举。允许收集 要由多个线程访问的 阅读和写作,你必须 实现您自己的同步 “枚举集合本质上不是线程安全过程。” 这句话让我担心 这是否意味着它对于只读场景是线程安全的,但前提是不使用枚举 或者对我的场景来说安全吗C#List的线程安全性<;T>;给读者,c#,list,thread-safety,generic-list,C#,List,Thread Safety,Generic List,我计划在静态构造函数中创建一次列表,然后让该类的多个实例在不进行任何锁定的情况下并发地读取(并枚举) 本文 MS将螺纹安全问题描述如下: 公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 任何实例成员都不是 保证线程安全 一个列表可以支持多个读卡器 同时,只要 集合未被修改。 在集合中枚举是不正确的 本质上不是线程安全的 程序在罕见的情况下 枚举与一个或多个 写访问,这是确保 螺纹的安全性在于锁紧螺纹 在整个过程中收集 枚举。允许收集 要由多个线程访问的 阅读和写作,你必
谢谢你的回答。 如果AsReadOnly可以使用或不使用,为什么我需要使用它呢 这是否意味着它是线程安全的 仅适用于读者场景,但只要 因为您不使用枚举?或者是 对我的场景来说安全吗 完全取决于您何时写入集合。这不能与没有某种锁定方案的读取(枚举)一致 因此,如果您只填充一次,然后只对其进行迭代,那么您就安全了。但是,当一个线程更改列表(添加或删除项目)时,您将需要例如ReaderWriterLockSlim
更改存储项的状态时,线程安全与该项(而不是列表)有关 这意味着,如果您枚举一个集合,而另一个线程(或您自己的线程)更改了它,那么您将遇到问题
只要您根本不更改集合,只要您不跨线程共享
IEnumerator
,您就不会有任何问题。是的,列表对于仅读者场景是安全的,如果列表永远不会被修改,那么它就可以了
如果事实上在构建后列表不会被修改,那么您应该使用更合适的界面,如ReadOnlyCollection
。如果它像您所说的那样存储在公共静态变量中,则应该使用该接口
private static List<T> shared_list;
private static ReadOnlyCollection<T> _data;
public static IEnumerable<T> Data
{
get
{
return _data ?? (_data = shared_list.AsReadOnly());
}
}
私有静态列表共享\u列表;
私有静态只读收集数据;
公共静态IEnumerable数据
{
得到
{
返回_data???(_data=shared_list.AsReadOnly());
}
}
==编辑====
此版本缓存ReadOnlyCollection引用,以加快将来的查找时间
请注意,如果两个线程在引用为null时同时尝试获取引用,则可能会在_data变量上发生数据争用,但因为所有内容都是只读的,所以这并不重要,我们只会创建一个额外的ReadOnlyCollection对象,这比同步便宜。请注意,您仍然不能更改原始列表。另外,不要每次获取属性时都调用
AsReadOnly
。根据MSDN文档,AsReadOnly是一个O(1)操作。我相信它只是用一个ReadOnlyCollection来包装,它只是简单地委托给基础集合。所以AsReadOnly应该非常快,但它确实会导致分配,所以我们可以潜在地共享那个内存。我将编辑以反映。在.NET4下,您可以使用泛型惰性类进行初始化。参见不跨线程共享IEnumerators
您的意思是不从多个线程访问**同一个枚举器实例**吗?@EugeneBeresovksy:完全正确。