C# 属性 setter 是临界区吗?

Are C# property setter critical regions?

我的问题很简短:
C# 属性 setter 是临界区,还是我应该自己实现临界区?

下面是一些示例代码:

public class MyClass
{
    private int _myProperty;

    public int MyProperty
    {
        get { return _myProperty; }

        set
        {
            //required: start critical section 
            _myProperty = value;
            Do1();
            Do2();
            //required: end critical section 
        }
    }

    protected virtual void Do1()
    {
        //...
    }

    protected virtual void Do2()
    {
        //...
    }
}

,属性不是隐式线程安全。

一个原因是为了非原子操作的线程安全,你需要锁定一个监视器对象(如在lock语句中)。这是哪个对象,锁定多长时间取决于您的要求。因此,编译器无法自动为您决定。

另一个原因是线程安全具有相当大的性能成本。如果您没有并发代码,这些成本将毫无益处。因此,编译器也不会自动为您做出决定。

(实际上,属性并没有什么特别之处。它们通常作为普通的 get/set 方法实现。语法和工具中的任何特殊处理都只是约定俗成。)

您应该自己实现关键区域,因为上下文切换可能发生在您的线程设置 属性 之后但在您处理 Do1() 和 Do2() 之前。另一个获得处理时间的线程现在可以覆盖您的 属性。

使用锁来保护 setter:

private Object setMyPropertyLock = new Object()

public int MyProperty
{
    get { return _myProperty; }

    set
    {
        lock(setMyPropertyLock)
        {
            _myProperty = value;
            Do1();
            Do2();
        }
    }
}