C# 是列表<;T>;。AddRange()线程安全吗?
在不锁定的情况下,我可以从多个线程安全地调用List.AddRange(r)吗?如果不是,我会遇到什么样的问题?否,并没有说它是线程安全的,因此它不是 公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 任何实例成员都不是 保证线程安全 至于可能出现的问题,请考虑AddRange(newItems)的功能:C# 是列表<;T>;。AddRange()线程安全吗?,c#,multithreading,collections,thread-safety,C#,Multithreading,Collections,Thread Safety,在不锁定的情况下,我可以从多个线程安全地调用List.AddRange(r)吗?如果不是,我会遇到什么样的问题?否,并没有说它是线程安全的,因此它不是 公共静态(在Visual Basic中共享) 此类型的成员是线程安全的。 任何实例成员都不是 保证线程安全 至于可能出现的问题,请考虑AddRange(newItems)的功能: 检查内部阵列中是否有足够的空间 如果没有: 分配一个新数组 将当前项复制到新阵列 将字段设置为指向新阵列 将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。谢谢你的投票。我想让您知道,我编辑了我的答案,以反映您(我们所有人)提供给我的新信息。顺便说一句,您可能会遇到“什么样的问题?”-在多线程冲突的某个随机时间,您可能会遇到异常