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

enz*_*m83 8 .net c# multithreading thread-safety

我读了一些关于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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  1. 不应通过公共属性公开任何私有SyncRoot对象; 换句话说,自定义数据结构不应提供公共SyncRoot属性(另请参阅此注释).
  2. 通常,不必使用私有对象进行锁定(请参阅此答案).
  3. 如果一个类有多组需要同步但彼此不同步的操作,它应该有多个私有SyncRoot对象(请参阅此注释).

上面写的是正确使用这种模式的吗?

ole*_*sii 4

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

  • 我这种类型的用户可能需要使用不同的同步机制,例如Mutex, 或ReaderWriterLockReaderWriterLockSlim

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

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

    public object SyncRoot {get {return this;}}
    
    Run Code Online (Sandbox Code Playgroud)

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