读者的C#List <t>的线程安全性</t>

时间:2010-05-12 21:46:59

标签: c# list thread-safety generic-list

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

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

  

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

     

列表可以支持多个读者   同时,只要   集合未被修改。   列举一个集合是   本质上不是线程安全的   程序。在罕见的情况下   枚举与一个或多个竞争   写访问,唯一的方法来确保   线程安全是锁定   整个收集   列举。允许收集   由多个线程访问   读书和写作,你必须   实现自己的同步。

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

这是否意味着它仅对于读者而言是线程安全的,但只要您不使用枚举?

或者我的情况安全吗?


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

3 个答案:

答案 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。

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