我计划在静态构造函数中创建一次列表,然后让该类的多个实例同时读取它(并通过它进行枚举),而不进行任何锁定。
在这篇文章中 http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx MS描述了线程安全问题如下:
公共静态(在Visual Basic中共享) 这种类型的成员是线程安全的。 任何实例成员都不是 保证是线程安全的。
列表可以支持多个读者 同时,只要 集合未被修改。 列举一个集合是 本质上不是线程安全的 程序。在罕见的情况下 枚举与一个或多个竞争 写访问,唯一的方法来确保 线程安全是锁定 整个收集 列举。允许收集 由多个线程访问 读书和写作,你必须 实现自己的同步。
在 “通过集合枚举本质上不是一个线程安全的过程。” 声明让我担心。
这是否意味着它仅对于读者而言是线程安全的,但只要您不使用枚举?
或者我的情况安全吗?
感谢您的回答。 为什么我需要使用AsReadOnly,如果它可以使用或不使用它?
答案 0 :(得分:8)
他们的意思是,如果你在一个不同的线程(或你自己的线程)改变它时枚举一个集合,你就会遇到问题。
只要您根本不更改集合,并且只要您不跨线程共享IEnumerator
,就不应该有任何问题。
答案 1 :(得分:3)
是的,该列表对于仅限读者方案是安全的,如果列表永远不会被修改,那么它就可以了。
如果实际上是在构建后不会修改列表的情况,那么您应该使用更合适的界面,如ReadOnlyCollection
。如果它存储在公共静态变量中,你应该使用该接口。
private static List<T> shared_list;
private static ReadOnlyCollection<T> _data;
public static IEnumerable<T> Data
{
get
{
return _data ?? (_data = shared_list.AsReadOnly());
}
}
==== EDIT ====
此版本缓存ReadOnlyCollection引用,以便更快地查看未来的查找时间。
注意,如果两个线程在null为空时尝试同时获取引用,则有可能在_data变量上发生数据争用,但由于所有内容都是只读的,这并不重要,我们只需要创建一个额外的ReadOnlyCollection对象,与同步相比便宜。
答案 2 :(得分:1)
这是否意味着它是线程安全的 仅适用于读者的场景,但同样长 因为你不使用枚举?或者是 我的情况安全吗?
完全取决于您何时写入该集合。如果没有某种锁定方案,这与读取(枚举)不一致。
因此,如果你填一次然后只迭代它,你就安全了。但是当一个线程更改列表(添加或删除项目)时,您将需要一个ReaderWriterLockSlim。
当您更改存储项目的状态时,线程安全性与该项目(而不是列表)有关。