C# 是列表<;T>;。AddRange()线程安全吗?

C# 是列表<;T>;。AddRange()线程安全吗?,c#,multithreading,collections,thread-safety,C#,Multithreading,Collections,Thread Safety,在不锁定的情况下,我可以从多个线程安全地调用List.AddRange(r)吗?如果不是,我会遇到什么样的问题?否,并没有说它是线程安全的,因此它不是 公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 任何实例成员都不是 保证线程安全 至于可能出现的问题,请考虑AddRange(newItems)的功能: 检查内部阵列中是否有足够的空间 如果没有: 分配一个新数组 将当前项复制到新阵列 将字段设置为指向新阵列 将newItems复制到内部数组中正确的本地 更新“计数

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

,并没有说它是线程安全的,因此它不是

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

至于可能出现的问题,请考虑AddRange(newItems)的功能:

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

现在想一想,如果上述操作与对AddRange()的另一个调用,甚至只是一个读取项目的调用混合在一起,会发生什么

不,它不是线程安全的

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


线程B可以在线程A完成之前调用Add/Remove等。

不,不是这样,但我想补充的是,执行
myList.AddRange(…)更有效比做几个
锁(syncLock){myList.Add(…)}

你会遇到什么样的麻烦?当一个线程正在添加一个项目,而另一个线程正在枚举列表时,
list
将抛出一个特定的异常,因为它执行一些内部版本控制,因为它希望防止我们这些糟糕的开发人员遇到令人讨厌的副作用

此外,
列表
在内部保留一个数组,用于存储其项。也许在数组中设置一个项目是非常原子化的,但是每当达到这个数组的容量时,就会创建一个新的数组,并从旧数组复制项目。因此,当一个线程要在复制过程中添加某些内容时,可以想象事情会失去同步。

在.NET Framework 4.0之前,没有.NET集合是线程安全的。然后,您需要在代码中访问它之前锁定它

另一方面,.NET Framework 4.0引入了新的名称空间,其中包括细粒度的名称空间

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

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

编辑#1

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

  • )
  • )
  • 很抱歉,我自己刚学会了他们的存在

    根据您的使用情况,可能会起作用


    不过,你不会有单次射击
    AddRange
    。如果您仅使用它来为集合设定种子,则可以执行此操作,因为存在
    IEnumerable
    构造函数重载。

    不正确,在
    System.Collections.Generic
    中有一些在4之前在这里起作用。0@Steve汤森德:经过核实,你是对的,我错了。此外,
    IList
    通用集合不是,尽管我没有考虑过这个
    SynchronizedCollection
    ,因为我不知道它=P谢谢你通知我!没问题。提到4.0系列,我欠你一个+1。谢谢你的投票。我想让您知道,我编辑了我的答案,以反映您(我们所有人)提供给我的新信息。顺便说一句,您可能会遇到“什么样的问题?”-在多线程冲突的某个随机时间,您可能会遇到异常