ReadOnlyCollection(T)的文档声明:
A ReadOnlyCollection(Of T)
可以同时支持多个读者,只要不修改集合即可。即便如此,通过集合枚举本质上不是一个线程安全的过程。为了在枚举期间保证线程安全,您可以在整个枚举期间锁定集合。要允许多个线程访问集合以进行读写,您必须实现自己的同步。
我的问题是关于粗体部分:
答案 0 :(得分:7)
C#有一个非常好的集合模型,但ReadOnlyCollection类是整个模型中最不幸构思(或命名)的类之一。它应该更恰当地称为只读列表,而不是只读集合。
现在,为了解决您的问题,它只是在构造时提供的IList的只读装饰器。因此,构造ReadOnlyCollection的代码可能会修改原始列表,并具有多线程访问所带来的所有后果。
因此,如果集合是真正的只读,那么通过集合枚举将是线程安全的;但由于它不是只读的,因此它不是线程安全的。鉴于您拥有的声誉数量,我很确定您不会想知道为什么通过非只读集合进行枚举不是线程安全的。
至于你问的解决方法,你可以使用锁定,或者你可以使用lock-nothing(或尽可能少的锁定)原则并制作一个真正的只读副本清单。
修改强>
我几个月后重新阅读了我的答案,(感谢asyncwait的评论),我意识到我应该回答所有OP的问题而不根据他的声誉做出假设。 OP现在可能已收到他的答案,但我会为了未来的读者而这样做。
枚举非真正只读集合本质上不是线程安全的,原因相同,即使在单线程场景中,您也无法在枚举时修改集合。 (Java中的ConcurrentModificationException,C#中的InvalidOperationException。)在单线程场景中,您可以确保您的枚举代码不会以任何方式尝试更改集合,但在多线程场景中,一个线程可能正在枚举集合另一个线程可能正在同时改变它。
答案 1 :(得分:3)
此MSDN article staes:“ReadOnlyCollection泛型类的实例始终是只读的。只读集合只是一个带有包装器的集合,可以防止修改集合“
所以我认为迭代不是线程安全的,因为它在内部使用普通的非线程安全的对象集合。
其含义是,如果集合发生变化,不同的线程可能会获得不同的值。使用lock
语句可以避免同时从不同的线程同时访问集合。
答案 2 :(得分:0)
在其他帖子中回答了问题1和2。