13

我计划在静态构造函数中创建一次列表,然后让该类的多个实例同时读取它(并通过它枚举)而不做任何锁定。

在这篇文章 http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx 中,MS 描述了线程安全问题如下:

此类型的公共静态(在 Visual Basic 中为 Shared)成员是线程安全的。不保证任何实例成员都是线程安全的。

只要集合没有被修改,一个 List 可以同时支持多个读取器。通过集合进行枚举本质上不是线程安全的过程。在枚举与一个或多个写访问竞争的极少数情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。要允许集合被多个线程访问以进行读写,您必须实现自己的同步。

“通过集合枚举本质上不是线程安全的过程。” 声明是我担心的。

这是否意味着它对读者来说是线程安全的,但只要你不使用枚举?

或者对我的场景安全吗?


感谢您的回答。如果它可以使用或不使用它,为什么我需要使用 AsReadOnly?

4

3 回答 3

9

他们的意思是,如果您枚举一个集合,而另一个线程(或您自己的线程)更改它,您将遇到问题。

只要你根本不改变集合,只要你不IEnumerator跨线程共享 s,你应该没有任何问题。

于 2010-05-12T21:50:49.897 回答
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());
    }
}

====编辑====

此版本缓存了 ReadOnlyCollection 参考,以加快未来的查找时间。

请注意,如果 _data 变量为空时两个线程尝试同时获取引用,则可能会在 _data 变量上发生数据竞争,但是因为所有内容都是只读的,这并不重要,我们将创建一个额外的 ReadOnlyCollection对象,与同步相比便宜。

于 2010-05-12T21:53:09.797 回答
1

这是否意味着它对读者来说是线程安全的,但只要你不使用枚举?或者对我的场景安全吗?

完全取决于您何时写入集合。如果没有某种锁定方案,这与读取(枚举)是不一致的。

因此,如果您填充一次然后仅对其进行迭代,那么您是安全的。但是当一个线程更改列表(添加或删除项目)时,您将需要例如 ReaderWriterLockSlim。

当您更改存储项目的状态时,线程安全性与该项目(而不是列表)有关。

于 2010-05-12T21:50:21.340 回答