C# 列表的线程安全版本-实现

C# 列表的线程安全版本-实现,c#,.net,multithreading,parallel-processing,task-parallel-library,C#,.net,Multithreading,Parallel Processing,Task Parallel Library,在阅读了大量关于堆栈溢出的文章之后,我认为我能够找到一个线程安全版本的List,它肯定达不到并发集合的级别,因为它使用了ReaderWriterLockSlim,但据我所知,它工作正常,与简单锁版本相比性能更好。您认为可以在当前实现中改进的任何内容。它仍然没有实现List的所有功能,因为我刚刚处理了IList 免责声明-我从堆栈溢出中得到了灵感,所以它肯定包含了来自不同帖子的部分 修改-修改代码以考虑某些场景,这些场景在上次通信中发布,如: if(list.count > 0) ret

在阅读了大量关于堆栈溢出的文章之后,我认为我能够找到一个线程安全版本的List,它肯定达不到并发集合的级别,因为它使用了ReaderWriterLockSlim,但据我所知,它工作正常,与简单锁版本相比性能更好。您认为可以在当前实现中改进的任何内容。它仍然没有实现List的所有功能,因为我刚刚处理了IList

免责声明-我从堆栈溢出中得到了灵感,所以它肯定包含了来自不同帖子的部分

修改-修改代码以考虑某些场景,这些场景在上次通信中发布,如:

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();
        }
    }
}

这种实现有点漏洞百出,因为即使每个原子操作(例如每个方法调用)都是线程安全的,但总体上还是容易出错的

来说明,考虑这种代码:

if(!myThreadSafeList.Contains(item))
       myThreadSafeList.Add(item);
这两个操作是线程安全的,但总体上不是

正如trailmax在评论中建议的那样,您可以使用.Net Concurent集合

另一种选择是在Nuget上提供

这些是线程安全的,而且没有锁


Ps:如果你打算使用不可变的集合,尽管。。。使用方法在C中实现。

为什么不只使用.Net并发集合?问题是什么?这个问题似乎与主题无关,因为它是关于CodeReview的。主要问题是没有使每个方法都是线程安全的,这很容易。它使包含多个方法调用的整个操作以一致的方式运行。@trailmax最近的是ConcurrentBag,它不是真正意义上的列表,因为它没有为数据提供有序索引方法。事实上,并提供另一个示例代码,如if list.Count>0 return list[0];完全同意,但我将告诉您一个场景,即使是并发集合和不可变列表也会失败。我的系统上有一个outlook客户端,我的手机上也配置了相同的邮件,因此我多次删除手机上的邮件,但它位于系统的outlook界面中,单击它会由于已知原因出现未知错误。与我的应用程序类似,是否有任何集合可用于此场景,事实上,此场景需要实时检查和更新接口,在当前情况下,我只需要包装上述异常case@MrinalKamboj这不是一个反例,这是关于同步访问您的邮件帐户,与并发收集无关。@Dirk请解释跨设备的同步访问Windows系统、Android手机,您将如何解决上述情况。要么它必须进行投票和更新,要么创建一个通知系统,但这两种方式都是昂贵的,我没有看到微软Outlook这样做,而安卓这样做是为了取缔Versa@MrinalKamboj并发集合或使集合访问线程安全是指单个进程内的并发访问。要在另一个进程中或甚至在另一个设备上更新数据,您需要推送或拉送方法,这两种方法都不是问题或答案的主题。