完全编辑早期版本,以下实现可以是“线程安全列表”实现。我只需要知道它是否真的可以线程安全,就性能而言我仍然会遇到问题。当前版本使用ReaderWriterLockSlim,我还有另一个使用Lock的实现,执行相同的工作
使用System.Collections.Generic;
使用System.Threading;
/// <summary>
/// Thread safe version of the List using ReaderWriterLockSlim
/// </summary>
/// <typeparam name="T"></typeparam>
public class ThreadSafeListWithRWLock<T> : IList<T>
{
// Internal private list which would be accessed in a thread safe manner
private List<T> internalList;
// ReaderWriterLockSlim object to take care of thread safe acess between multiple readers and writers
private readonly ReaderWriterLockSlim rwLockList;
/// <summary>
/// Public constructor with variable initialization code
/// </summary>
public ThreadSafeListWithRWLock()
{
internalList = new List<T>();
rwLockList = new ReaderWriterLockSlim();
}
/// <summary>
/// Get the Enumerator to the Thread safe list
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return Clone().GetEnumerator();
}
/// <summary>
/// System.Collections.IEnumerable.GetEnumerator implementation to get the IEnumerator type
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Clone().GetEnumerator();
}
/// <summary>
/// Clone method to create an in memory copy of the Thread safe list
/// </summary>
/// <returns></returns>
public List<T> Clone()
{
List<T> clonedList = new List<T>();
rwLockList.EnterReadLock();
internalList.ForEach(element => { clonedList.Add(element); });
rwLockList.ExitReadLock();
return (clonedList);
}
/// <summary>
/// Add an item to Thread safe list
/// </summary>
/// <param name="item"></param>
public void Add(T item)
{
rwLockList.EnterWriteLock();
internalList.Add(item);
rwLockList.ExitWriteLock();
}
/// <summary>
/// Remove an item from Thread safe list
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Remove(T item)
{
bool isRemoved;
rwLockList.EnterWriteLock();
isRemoved = internalList.Remove(item);
rwLockList.ExitWriteLock();
return (isRemoved);
}
/// <summary>
/// Clear all elements of Thread safe list
/// </summary>
public void Clear()
{
rwLockList.EnterWriteLock();
internalList.Clear();
rwLockList.ExitWriteLock();
}
/// <summary>
/// Contains an item in the Thread safe list
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
bool containsItem;
rwLockList.EnterReadLock();
containsItem = internalList.Contains(item);
rwLockList.ExitReadLock();
return (containsItem);
}
/// <summary>
/// Copy elements of the Thread safe list to a compatible array from specified index in the aray
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(T[] array, int arrayIndex)
{
rwLockList.EnterReadLock();
internalList.CopyTo(array,arrayIndex);
rwLockList.ExitReadLock();
}
/// <summary>
/// Count elements in a Thread safe list
/// </summary>
public int Count
{
get
{
int count;
rwLockList.EnterReadLock();
count = internalList.Count;
rwLockList.ExitReadLock();
return (count);
}
}
/// <summary>
/// Check whether Thread safe list is read only
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Index of an item in the Thread safe list
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
int itemIndex;
rwLockList.EnterReadLock();
itemIndex = internalList.IndexOf(item);
rwLockList.ExitReadLock();
return (itemIndex);
}
/// <summary>
/// Insert an item at a specified index in a Thread safe list
/// </summary>
/// <param name="index"></param>
/// <param name="item"></param>
public void Insert(int index, T item)
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1 && index >= 0)
internalList.Insert(index,item);
rwLockList.ExitWriteLock();
}
/// <summary>
/// Remove an item at a specified index in Thread safe list
/// </summary>
/// <param name="index"></param>
public void RemoveAt(int index)
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1 && index >= 0)
internalList.RemoveAt(index);
rwLockList.ExitWriteLock();
}
/// <summary>
/// Indexer for the Thread safe list
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
T returnItem = default(T);
rwLockList.EnterReadLock();
if (index <= internalList.Count - 1 && index >= 0)
returnItem = internalList[index];
rwLockList.ExitReadLock();
return (returnItem);
}
set
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1 && index >= 0)
internalList[index] = value;
rwLockList.ExitWriteLock();
}
}
}
最佳答案
实现封装线程安全性的自定义List<T>
很少值得付出。每当访问lock
时,最好只使用List<T>
。
但是我本人是一个绩效密集型行业,因此有时会成为瓶颈。 lock
的主要缺点是可能进行上下文切换,相对而言,这在挂钟时间和CPU周期上都非常昂贵。
解决此问题的最佳方法是使用不变性。让所有读者访问一个不可变的列表,并让作家使用Interlocked
操作“更新”它,以新实例替换它。这是一种无锁设计,可以使读取无同步,而写入无锁(消除了上下文切换)。
我要强调的是,在几乎所有情况下,这都是矫kill过正的,除非您肯定需要,并且您了解缺点,否则我什至不会考虑走这条路。几个明显的例子是读者获取时间点快照并浪费了内存来创建副本。
ImmutableList中的Microsoft.Bcl.Immutable也值得一看。这是完全线程安全的。
关于c# - 使用Reader Writer Lock创建线程安全列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25681321/