我有一个实现ICollection
的自定义类,这个类是readonly,即。 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问题?您可以通过此实现看到任何其他问题吗?
答案 0 :(得分:4)
是的,在某些情况下这是一个问题。即使集合是只读的并且无法更改,集合引用的对象也不是只读的。因此,如果客户端使用SyncRoot执行锁定,则在修改集合引用的对象时,它们将不是线程安全的。
我建议添加:
private readonly object syncRoot = new object();
到你的班级。将此作为SyncRoot返回,你很高兴。
答案 1 :(得分:2)
我想问题是如果客户端使用你的同步根来实现锁定你的集合,而不是其他东西。假设他们缓存了集合的大小 - 或者“这个集合的哪个子集匹配谓词” - 他们会合理地假设他们可以使用你的SyncRoot来保护你的集合和他们的其他成员。
就个人而言,我根本不使用SyncRoot,但我认为总是返回相同的东西是明智的。
答案 2 :(得分:2)
每次返回一个不同的对象似乎很奇怪......实际上,我很少(如果有的话)使用SyncRoot方法,因为我经常需要在多个对象之间进行同步,因此单独的对象更有意义。
但是如果数据真的是不可变的(readonly),为什么不从IsSynchronized返回false?
Re GC - 任何此类对象通常都是短暂的,并在GEN0中收集。如果你有一个带有对象的字段(对于锁),它会持续与集合一样长,但最有可能不会受到伤害......
如果你需要锁定,我很想得到一个:
private readonly object lockObj = new object();
你也可以在需要的时候使用懒惰的方法只是“新”它,如果你实际上不希望任何人要求同步锁(通过返回false到IsSynchronized),这有一定的意义。 / p>
另一种常见方法是返回“this”;它使事情变得简单,但是冒险与其他代码冲突,使用您的对象作为不相关目的的锁。很少见,但可能。这实际上是[MethodImpl]
用于同步的方法。