List <t> .AddRange()线程是否安全?</t>

时间:2010-10-28 14:06:53

标签: c# multithreading collections thread-safety

我可以在没有锁定的情况下从多个线程安全地调用List.AddRange(r)吗?如果没有,我会遇到什么样的麻烦?

5 个答案:

答案 0 :(得分:17)

its documentation并未表示它是线程安全的,因此不是。

  

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

关于可能出现的问题,请考虑AddRange(newItems)的作用:

  • 检查内部阵列中是否有足够的空间
  • 如果不是:
    • 分配新阵列
    • 将当前项目复制到新阵列
    • 将字段设置为指向新数组
  • 将newItems复制到内部数组中的正确本地
  • 更新“count”字段(用于控制下一个项目的插入位置)

现在想想如果上面的内容与另一个AddRange()调用混合在一起甚至只是调用一个项目,会发生什么。

答案 1 :(得分:6)

不,不是,但是我想在锁内做myList.AddRange(...);比做几个lock (syncLock) { myList.Add(...) };更有效率。

你会遇到哪种麻烦?当一个线程正在添加一个项目而另一个线程正在枚举列表时,List<T>将抛出某个异常,因为它会进行一些内部版本控制,因为它希望阻止我们的开发人员遇到令人讨厌的副作用。

此外List<T>内部保留一个数组,用于存储其项目。也许在数组中设置一个项目是非常原子的,但是每当达到此数组的容量时,将创建一个新项目,并且将从旧项目中复制项目。因此,当一个线程想要在复制过程中添加一些东西时,你可以想象事情会不同步。

答案 2 :(得分:3)

在.NET Framework 4.0之前,没有.NET集合是线程安全的。在您使用代码Collections and Synchronization (Thread Safety)访问它之前,您需要锁定它。

另一方面,.NET Framework 4.0引入了新的System.Collections.Concurrent命名空间,其中包含细粒度的Thread-Safe Collections

最后,如果您可以使用.NET Framework 4.0,我强烈建议您根据需要执行此操作,否则,请确保每次要修改或访问它时都锁定该集合。

此外,静态集合应该是线程安全的,但要注意,因为不保证成员。

编辑#1

根据Steve Townsend的评论进一步验证后,我承认.NET Framework中有三个线程安全的集合,从3.0版本开始:

  1. SynchronizedCollection Generic Class;
  2. SynchronizedKeyedCollection Generic Class;
  3. SynchronizedReadOnlyCollection Generic Class
  4. 我道歉,我自己刚刚学会了退出。 =)

答案 3 :(得分:3)

根据您的使用情况,SynchronizedCollection可能有效。

但你没有单发AddRange。如果您只是使用它来为集合设定种子,则可以执行此操作,因为IEnumerable构造函数已超载。

答案 4 :(得分:1)

不,它不是线程安全的。

线程A可以在列表中调用AddRange。它可以部分迭代集合并切换线程。

线程B可以在线程A完成之前调用添加/删除等。