经过Stack Overflow上的大量帖子后,我想我能够提出一个线程安全版本的List,这肯定不符合Concurrent集合的水平,因为它使用了ReaderWriterLockSlim,但在我的理解,与简单的锁定版本相比,它按预期工作并具有更好的性能。您可能认为的任何内容都可以在当前的实现中得到改进。它仍然没有实现List的所有功能,因为我刚刚处理了IList
免责声明 - 我从Stack Overflow中得到了一些想法,所以它肯定包含来自不同帖子的点点滴滴
修改 - 修改代码以处理某些情况,这些情景在上次通信中发布,如:
if(list.count > 0)
return list[0]
没有理由将此标记为关闭主题
线程安全实施
using System.Collections.Generic;
using System.Threading;
/// <summary>
/// Thread safe version of the List using
/// </summary>
/// <typeparam name="T"></typeparam>
public class ThreadSafeListWithRWLock<T> : IList<T>
{
private List<T> internalList;
private readonly ReaderWriterLockSlim rwLockList;
public ThreadSafeListWithRWLock()
{
internalList = new List<T>();
rwLockList = new ReaderWriterLockSlim();
}
// Other Elements of IList implementation
public IEnumerator<T> GetEnumerator()
{
return Clone().GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return Clone().GetEnumerator();
}
public List<T> Clone()
{
List<T> clonedList = new List<T>();
rwLockList.EnterReadLock();
internalList.ForEach(element => { clonedList.Add(element); });
rwLockList.ExitReadLock();
return (clonedList);
}
public void Add(T item)
{
rwLockList.EnterWriteLock();
internalList.Add(item);
rwLockList.ExitWriteLock();
}
public bool Remove(T item)
{
bool isRemoved;
rwLockList.EnterWriteLock();
isRemoved = internalList.Remove(item);
rwLockList.ExitWriteLock();
return (isRemoved);
}
public void Clear()
{
rwLockList.EnterWriteLock();
internalList.Clear();
rwLockList.ExitWriteLock();
}
public bool Contains(T item)
{
bool containsItem;
rwLockList.EnterReadLock();
containsItem = internalList.Contains(item);
rwLockList.ExitReadLock();
return (containsItem);
}
public void CopyTo(T[] array, int arrayIndex)
{
rwLockList.EnterReadLock();
internalList.CopyTo(array,arrayIndex);
rwLockList.ExitReadLock();
}
public int Count
{
get
{
int count;
rwLockList.EnterReadLock();
count = internalList.Count;
rwLockList.ExitReadLock();
return (count);
}
}
public bool IsReadOnly
{
get { return false; }
}
public int IndexOf(T item)
{
int itemIndex;
rwLockList.EnterReadLock();
itemIndex = internalList.IndexOf(item);
rwLockList.ExitReadLock();
return (itemIndex);
}
public void Insert(int index, T item)
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1)
internalList.Insert(index,item);
rwLockList.ExitWriteLock();
}
public void RemoveAt(int index)
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1)
internalList.RemoveAt(index);
rwLockList.ExitWriteLock();
}
/// <summary>
///
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
T returnItem = default(T);
rwLockList.EnterReadLock();
if (index <= internalList.Count - 1)
returnItem = internalList[index];
rwLockList.ExitReadLock();
return (returnItem);
}
set
{
rwLockList.EnterWriteLock();
if (index <= internalList.Count - 1)
internalList[index] = value;
rwLockList.ExitWriteLock();
}
}
}
答案 0 :(得分:8)
这种实现有点漏洞,因为即使每个原子操作(例如每个方法调用)都是线程安全的,整体也容易出错。
为了说明,请考虑这种代码:
if(!myThreadSafeList.Contains(item))
myThreadSafeList.Add(item);
这两个操作是线程安全的,但整体不是。
你可以使用.Net conccurent集合,正如trailmax在评论中所建议的那样。
另一种选择是to use Microsoft immutable collection,可在Nuget上找到。
这些是线程安全的,而且,无锁!
Ps:如果您打算使用不可变集合,请了解compare-and-swap loops,但是......使用Interlocked.CompareExchange方法在C#中实现。