关于SyncRoot模式的一些说明:使用此模式的正确方法是什么?

时间:2012-09-14 12:53:16

标签: c# .net multithreading thread-safety

我读了一些关于 SyncRoot模式的内容,作为避免死锁的一般规则。阅读几年前的问题(见link),我想我明白这种模式的一些用法可能是不正确的。特别是,我专注于this topic中的以下句子:

  

您会注意到System.Collections中许多集合的SyncRoot属性。在回顾中,我认为这个属性是一个   错误......请放心,我们不会犯同样的错误   这些集合的通用版本。

事实上,例如,List<T>类不实现SyncRoot属性,或者更正确地实现它(请参阅this answer),因此必须强制转换为{{1为了使用它。但是this comment认为私有ICollection字段公开与锁定SyncRoot一样糟糕(请参阅this answer),同样在this comment中也已确认。 / p>

因此,如果我理解正确,当我实现非线程安全的数据结构时,由于它可以在多线程上下文中使用,我不应该(实际上,我不能)提供this属性。但是我应该让开发人员(将使用此数据结构)的任务是将其与私有SyncRoot对象相关联,如以下示例代码所示。

SyncRoot

总之,我了解同步/锁定的最佳实践应如下所示:

  1. 不应通过公共属性公开任何私有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 } } } 属性(另请参阅this comment)。
  2. 通常,不必使用私有对象进行锁定(请参阅this answer)。
  3. 如果一个类有多组需要同步但彼此不同步的操作,它应该有多个私有SyncRoot对象(参见this comment)。
  4. 上面写的正确使用了这种模式吗?

2 个答案:

答案 0 :(得分:4)

我会避免在我设计的类型中添加SyncRoot属性,原因如下:

  • 我的类型的用户可能需要使用不同的同步机制,例如MutexReaderWriterLockReaderWriterLockSlim

  • 这种类型变得更胖:它的责任变得更加分散。为什么我会添加对显式多线程锁定的支持而不支持其他的多线程?我会强迫用户只遵循一种做法,这可能不是所有情况下的最佳解决方案

  • 我需要正确实现该属性(不返回thistypeof(MyClass)),即这是错误的:

    public object SyncRoot {get {return this;}}
    

我也会避免使用.NET框架类型中的SyncRoot属性。如果我需要创建一个没有SyncRoot属性线程安全的类型,我将使用一个锁定模式,如果类型具有此属性,我仍然不会选择锁定SyncRoot。这使我的代码风格一致且易于阅读/维护。

答案 1 :(得分:0)

这里有很多概念。首先,您正确实现的是一个线程安全的类,其中没有类的消费者需要自己进行同步。因此,您绝对不需要公开syncRoot对象。在旧的Collection类中,暴露了SyncRoot属性,因为类是线程安全的。

在锁定任意对象并锁定内部集合时,在程序的正确性或性能方面绝对没有区别。只要对两者的引用都没有改变,它们的工作方式与Monitor.Enter / Exit的参数一样好。你的内心收藏会改变吗?如果不是,请将其标记为只读。

第三,有关于基于不同操作使用不同锁的评论。典型的例子是ReaderWriterLock。您应该根据类的不同功能分析是否需要使用不同级别的锁。