【发布时间】:2012-09-14 12:53:15
【问题描述】:
我阅读了一些关于 SyncRoot 模式 的内容,作为避免死锁的一般规则。阅读几年前的一个问题(见link),我想我理解这种模式的某些用途可能是不正确的。特别关注this topic的以下句子:
您会注意到 System.Collections 中许多集合上的 SyncRoot 属性。回想起来,我认为该物业是 错误...请放心,我们不会犯与我们构建相同的错误 这些集合的通用版本。
事实上,例如,List<T> 类没有实现SyncRoot 属性,或者更准确地说它是显式实现的(参见this answer),因此您必须强制转换为ICollection 才能使用它。但this comment 认为,将私有SyncRoot 字段设为公开与锁定this 一样糟糕(参见this answer),this comment 也证实了这一点。
所以,如果我理解正确,当我实现一个非线程安全的数据结构时,因为它可以在多线程上下文中使用,我不应该(实际上,我绝不能)提供SyncRoot 属性。但我应该让开发人员(将使用此数据结构)负责将其与私有 SyncRoot 对象相关联,如以下示例代码所示。
public class A
{
private MyNonThreadSafeDataStructure list;
private readonly object list_SyncRoot = new object;
public Method1()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
public Method2()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
}
总之,我理解同步/锁定的最佳实践应该如下:
- 不应通过公共属性公开任何私有 SyncRoot 对象;换句话说,自定义数据结构不应提供公共的
SyncRoot属性(另请参阅this comment)。 - 一般来说,使用私有对象进行锁定不是强制性的(请参阅this answer)。
- 如果一个类有多组操作需要同步,但不能相互同步,则它应该有多个私有 SyncRoot 对象(请参阅this comment)。
上面写的是否正确使用了这种模式?
【问题讨论】:
-
我的观点是,如果你想让一个类在内部是线程安全的,你可以在内部(私下)进行锁定,并证明这个类通常是线程安全的。否则,请不加锁,证明该类不是线程安全的,并让您的类的使用者根据具体用途的需要实现自己的锁定。
标签: c# .net multithreading thread-safety