ICollection、只读集合和同步。 这是正确的吗?
我有一个实现 ICollection 的自定义类,并且该类是只读的,即。 IsReadOnly
返回 true(与使用 readonly
关键字相反),并且所有通常会修改集合中数据的函数都会抛出 InvalidOperationException
的异常。
现在,考虑到这样的构造,并快速浏览一下实现 ICollection 时的线程安全问题(特别是 ICollection.IsSynchronized
和朋友),我想出了这个快速但肮脏的解决方案。
bool ICollection.IsSynchronised { get{ return true; } }
object ICollection.SyncRoot { get{ return new Object(); } }
现在,根据 MSDN 中的示例,这不会导致不同的线程正确锁定,因为它们从 SyncRoot 获取不同的对象。 鉴于这是一个只读集合,这是一个问题吗? 返回 new Object()
是否存在内存/GC 问题? 您还可以在此实施中发现其他问题吗?
I have a custom class that implements ICollection
, and this class is readonly, ie. IsReadOnly
returns true (as opposed to using the readonly
keyword), and all functions that would normally modify the data in the collection throw InvalidOperationException
's.
Now, given such a construct, and a quick skim over the thread-safety issues when implementing ICollection
(specifically ICollection.IsSynchronized
and friends), I came up with this quick and dirty solution.
bool ICollection.IsSynchronised { get{ return true; } }
object ICollection.SyncRoot { get{ return new Object(); } }
Now, given the examples in MSDN, this won't cause different threads to lock properly, because they are getting different objects from SyncRoot
. Given that this is a readonly collection though, is this an issue? Are there memory/GC issues with returning new Object()
? Any other issues you can see with this implementation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,在某些情况下这是一个问题。 尽管集合是只读的且无法更改,但集合引用的对象也不是只读的。 因此,如果客户端使用 SyncRoot 执行锁定,那么在修改集合引用的对象时它们将不是线程安全的。
我建议添加:
到你的班级。 将其作为 SyncRoot 返回,然后就可以开始了。
Yes this is an issue in some cases. Even though the collection is read only and cannot be changed, the objects the collection references are not read only. Thus if the clients use the SyncRoot to perform locking they will not be thread safe when modifying the objects referenced by the collection.
I would recommend adding:
to your class. Return this as the SyncRoot and you're good to go.
我想问题是,如果客户端使用您的同步根不仅可以锁定您的集合,还可以锁定其他内容。 假设他们缓存了集合的大小 - 或者可能是“该集合的哪个子集与谓词匹配” - 他们会合理地假设他们可以使用您的 SyncRoot 来保护您的集合和其他成员。
就我个人而言,我几乎不使用 SyncRoot,但我认为始终返回相同的内容是明智的。
I guess the issue would be if clients used your sync root to achieve locking of not only your collection, but something else. Supposed they cached the size of the collection - or maybe "what subset of this collection matches a predicate" - they would reasonably assume that they could use your SyncRoot to guard both your collection and their other member.
Personally I hardly use SyncRoot at all, but I think it would be sensible to always return the same thing.
每次返回不同的对象似乎很奇怪......实际上,我很少(如果有的话)使用 SyncRoot 方法,因为我经常需要在多个对象之间进行同步等,因此单独的对象更有意义。
但如果数据确实是不可变的(只读),为什么不直接从 IsSynchronized 返回 false 呢?
Re GC - 任何此类对象通常都是短暂的并被收集在 GEN0 中。 如果你有一个带有对象的字段(用于锁),它会与集合一样持续,但很可能不会造成伤害......
如果你需要一个锁,我会很想拥有一个:
您还可以使用惰性方法仅在需要时“新建”它,如果您实际上不希望任何人请求同步锁(通过向 IsSynchronized 返回 false ),这具有一定的意义。
另一种常见的方法是返回“this”; 它使事情变得简单,但存在与使用您的对象作为锁用于不相关目的的其他代码发生冲突的风险。 罕见,但有可能。 这实际上是
[MethodImpl]
用于同步的方法。It seems very odd to return a different object each time... actually, I very rarely (if ever) use the SyncRoot approach, as often I need to synchronize between multiple objects etc, so a separate object is more meaningful.
But if the data is truly immutable (readonly), why not just return false from IsSynchronized?
Re GC - any such object would typically be short lived and be collected in GEN0. If you have a field with an object (for the lock), it would last as long as the collection, but most likely won't hurt anyway...
If you need a lock, I'd be tempted to just have a:
You could also use a lazy approach to only "new" it when needed, which makes a certain amount of sense if you don't actually expect anyone to ask for the sync-lock (by returns false to IsSynchronized).
Another common approach is to return "this"; it keeps things simple, but risks conflicts with some other code using your object as a lock for an unrelated purpose. Rare, but possible. This is actually the approach that
[MethodImpl]
uses to synchronize.