作为一般规则,我阅读了一些关于SyncRoot 模式的内容,以避免死锁。阅读几年前的一个问题(请参阅此链接),我想我理解这种模式的某些用途可能是不正确的。特别是,我专注于该主题的以下句子:
您会注意到 System.Collections 中许多集合上的 SyncRoot 属性。回想起来,我认为这个属性是一个错误......请放心,我们不会犯同样的错误,因为我们构建了这些集合的通用版本。
实际上,例如,List<T>
类没有实现SyncRoot
属性,或者更准确地说,它是显式实现的(请参阅此答案),因此您必须转换ICollection
为才能使用它。但是此评论认为,SyncRoot
公开私有字段与锁定this
(请参阅此答案)一样糟糕的做法,正如此评论中所证实的那样。
所以,如果我理解正确,当我实现一个非线程安全的数据结构时,因为它可以在多线程上下文中使用,我不应该(实际上,我绝不能)提供该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
属性(另请参阅此评论)。 - 通常,不强制使用私有对象进行锁定(请参阅此答案)。
- 如果一个类有多个需要同步的操作集,但不能相互同步,则它应该有多个私有 SyncRoot 对象(请参阅此注释)。
上面写的是这个模式的正确使用吗?