Bat*_*rry 51 c# collections .net-4.0 thread-safety concurrent-collections
除了Concurrent Collections是命名空间还是一个类之外,命名空间中SynchronizedCollection<T>的并发集合如何System.Collections.Concurrent相互不同SynchronizedCollection<T>?
SynchronizedCollection<T>并发集合中的所有类都提供了线程安全的集合.我如何决定何时使用其中一个,为什么?
Cod*_*ray 59
该班首次推出.NET 2.0中提供一个线程安全的集合类.它通过锁定来实现这一点,因此您基本上可以将每个访问都包含在语句中.SynchronizedCollection<T>List<T>lock
该System.Collections.Concurrent命名空间是非常新的.它直到.NET 4.0才被引入,它包含了一个实质性改进和更多样化的选择.这些类不再使用锁来提供线程安全性,这意味着它们应该在多个线程同时访问其数据的情况下更好地扩展.但是,IList<T>在这些选项中尤其缺少实现该接口的类.
因此,如果您的目标是.NET Framework 4.0版,则应尽可能使用System.Collections.Concurrent命名空间提供的其中一个集合.就像在System.Collections.Generic命名空间中提供的各种类型的集合之间进行选择一样,您需要选择其特征和特征最适合您的特定需求的集合.
如果您的目标是.NET Framework的旧版本或需要实现该IList<T>接口的集合类,则必须选择SynchronizedCollection<T>该类.
MSDN上的这篇文章也值得一读:何时使用线程安全集合
这SynchronizedCollection<T>是一个同步的List<T>. 这是一个可以在一秒钟内设计出来,并且可以在大约一个小时内完全实施的概念。只需将 a 的每个方法包装List<T>在 a 内lock (this),就完成了。现在您有了一个线程安全的集合,它可以满足多线程应用程序的所有需求。但事实并非如此。
SynchronizedCollection<T>一旦你尝试用它做任何不平凡的事情,它的缺点就会变得明显。特别是当您尝试将集合的两个或多个方法组合起来进行概念上的单一操作时。然后您意识到该操作不是原子的,并且如果不诉诸显式同步(锁定SyncRoot集合的属性)就无法使其成为原子的,这破坏了集合的整个目的。一些例子:
if (!collection.Contains(x)) collection.Add(x);. 这段代码不能保证任何事情。Contains和之间固有的竞争条件Add允许重复发生。if (collection.Count < N) collection.Add(x);。Count和之间的竞争条件Add允许集合中存在超过 N 个元素。"Foo"用。。。来代替"Bar":int index = collection.IndexOf("Foo"); if (index >= 0) collection[index] = "Bar";。当线程读取 时index,其值立即失效。另一个线程可能会以指向某个其他元素的方式更改集合index,或者它超出范围。此时您意识到多线程比您最初想象的要求更高。在现有集合的 API 周围添加同步层并不能解决问题。您需要一个专为多线程使用而设计的集合,并且具有反映此设计的 API。这是在 .NET Framework 4.0 中引入并发集合的动机。
并发集合,例如 和ConcurrentQueue<T>,ConcurrentDictionary<K,V>是高度复杂的组件。它们比笨拙的要复杂几个数量级SynchronizedCollection<T>。它们配备了非常适合多线程环境( 、 等)的特殊原子 API TryDequeue,并且还具有旨在最大限度地减少大量使用情况下的争用的实现GetOrAdd。AddOrUpdate在内部,它们采用无锁、低锁和粒度锁技术。学习如何使用这些集合需要一些研究。它们不是非并发对应项的直接替代品。
注意: a 的枚举SynchronizedCollection<T>不同步。获取枚举器GetEnumerator是同步的,但使用枚举器不是同步的。因此,如果一个线程在另一个线程以任何方式(等)foreach (var item in collection)改变集合的同时,程序的行为是未定义的。枚举 a 的安全方法是获取集合的快照,然后枚举该快照。获取快照并不简单,因为它涉及两个方法调用(getter 和),因此需要显式同步。请注意 LINQ运算符,它本身不是线程安全的。下面是该类的安全扩展方法:AddRemoveSynchronizedCollection<T>CountCopyToToArrayToArraySafeSynchronizedCollection<T>
/// <summary>Copies the elements of the collection to a new array.</summary>
public static T[] ToArraySafe<T>(this SynchronizedCollection<T> source)
{
ArgumentNullException.ThrowIfNull(source);
lock (source.SyncRoot)
{
T[] array = new T[source.Count];
source.CopyTo(array, 0);
return array;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21889 次 |
| 最近记录: |