使用ReaderWriterLock创建一个线程安全的列表完全编辑的早期版本,下面的实现可以是一个线程安全的列表实现。我只需要知道它是否真的是线程安全的,我知道性能方面仍然存在问题。当前版本正使用ReaderWriterLockSlim,我有另一个使用Lock的现实,做同样的工作使用System.Collections.Generic;使用System.Threading;//////使用ReaderWriterLockSlim的List的线程安全版本//////publicclassThreadSafeListWithRWLock:IList{//将以线程安全方式访问的内部私有列表privateListinternalList;//ReaderWriterLockSlim对象负责多个读者和作者之间的线程安全访问privatereadonlyReaderWriterLockSlimrwLockList;//////带有变量初始化代码的公共构造函数///publicThreadSafeListWithRWLock(){internalList=newList();rwLockList=newReaderWriterLockSlim();}//////将枚举器获取到线程安全列表中//////publicIEnumeratorGetEnumerator(){returnClone().GetEnumerator();}//////System.Collections.IEnumerable.GetEnumerator实现获取IEnumerator类型//////System.Collections.IEnumeratorSystem.Collections.IEnumerable.GetEnumerator(){返回Clone().GetEnumerator();}//////Clone方法创建线程安全列表的内存副本//////publicListClone(){ListclonedList=newList();rwLockList.EnterReadLock();internalList.ForEach(element=>{clonedList.Add(element);});rwLockList.ExitReadLock();返回(克隆列表);}//////添加一个项目到线程安全列表//////publicvoidAdd(Titem){rwLockList.EnterWriteLock();内部列表。添加(项目);rwLockList.ExitWriteLock();}//////从线程安全列表中删除一个项目/////////publicboolRemove(Titem){boolisRemoved;rwLockList.EnterWriteLock();isRemoved=internalList.Remove(item);rwLockList.ExitWriteLock();返回(已移除);}//////清除线程安全列表的所有元素///publicvoidClear(){rwLockList.EnterWriteLock();internalList.Clear();rwLockList.ExitWriteLock();}//////包含线程安全列表中的一个项目/////////publicboolContains(Titem){布尔包含项;rwLockList.EnterReadLock();containsItem=internalList.Contains(item);rwLockList.ExitReadLock();返回(包含项目);}//////将线程安全列表的元素从数组中的指定索引复制到兼容数组/////////publicvoidCopyTo(T[]array,intarrayIndex){rwLockList.EnterReadLock();internalList.CopyTo(array,arrayIndex);rwLockList.ExitReadLock();}//////计数线程安全列表中的元素///publicintCount{get{intcount;rwLockList.EnterReadLock();count=internalList.Count;rwLockList.ExitReadLock();返回(计数);}}//////检查线程安全列表是否只读///publicboolIsReadOnly{get{returnfalse;}}//////线程安全列表中项目的索引/////////publicintIndexOf(Titem){intitemIndex;rwLockList.EnterReadLock();itemIndex=internalList.IndexOf(item);rwLockList.ExitReadLock();返回(项目索引);}//////在a处插入一个项目线程安全列表中的指定索引/////////publicvoidInsert(intindex,Titem){rwLockList.EnterWriteLock();如果(index=0)internalList.Insert(index,item);rwLockList。退出写锁();}//////删除线程安全列表中指定索引处的项目//////publicvoidRemoveAt(intindex){rwLockList.EnterWriteLock();如果(索引=0)内部列表。RemoveAt(索引);rwLockList.ExitWriteLock();}//////线程安全列表的索引器/////////publicTthis[intindex]{get{TreturnItem=default(T);rwLockList.EnterReadLock();如果(index=0)returnItem=internalList[index];rwLockList.ExitReadLock();返回(返回项);}设置{rwLockList.EnterWriteLock();如果(索引=0)内部列表[索引]=值;rwLockList.ExitWriteLock();}}}实现封装线程安全的自定义List几乎不值得付出努力每当您访问List时,最好只使用锁。但是,就我自己在性能密集型行业的案例而言,在某些情况下这会成为瓶颈。锁的主要缺点是上下文切换的可能性,这在挂钟时间和CPU周期上都相对昂贵。解决这个问题的最好方法是使用不变性。让所有读者访问不可变列表,作者使用互锁操作“更新”它以用新实例替换它。这是一种无锁设计,无需同步即可读取,无需锁定即可写入(消除上下文切换)。我要强调的是,在几乎所有情况下,这都是矫枉过正,我什至不会考虑走这条路,除非你确定你需要知道并且你理解缺点。一些明显的问题是读者拍摄时间点快照并浪费内存创建副本。Microsoft.Bcl.Immutable的ImmutableList也值得一看。它是完全线程安全的。这不是线程安全的。返回枚举器后,GetEnumerator()方法不持有任何锁,因此任何线程都可以自由使用返回的枚举器,而无需任何阻止它们这样做的锁定。通常,尝试创建线程安全的列表类型非常困难。请参阅此StackOverflow线程进行讨论:NoConcurrentListin.Net4.0?如果您尝试使用某种读取器/写入器锁定而不是简单的读写锁定方案,则并发读取的数量可能会大大超过您的写入数量。在这种情况下,Zer0建议的写时复制方法可能是合适的。在回答相关问题时,我发布了一个通用实用函数,它有助于将对任何数据结构的任何修改转换为线程安全和高度并发的操作。代码静态类CopyOnWriteSwapper{publicstaticvoidSwap(refTobj,Funccloner,Actionop)whereT:class{while(true){varobjBefore=Volatile.Read(refobj);varnewObj=cloner(objBefore);操作(新对象);如果(Interlocked.CompareExchange(refobj,newObj,objBefore)==objBefore)返回;}}}用法CopyOnWriteSwapper.Swap(ref_myList,orig=>newList(orig),clone=>clone.Add("asdf"));有关您可以使用它做什么的更多详细信息以及一些注意事项,可以在原始答案中找到。以上就是C#学习教程:使用ReaderWriterLock创建线程安全列表。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。涉及侵权,请点击维权联系管理员删除。如需转载请注明出处:
