如果线程安全方式不为null,则返回属性

时间:2015-12-16 10:48:22

标签: c# .net multithreading thread-safety

我的问题实际上是this的扩展。在返回属性之前,关于测试属性的问题是null。我有类似的情况:

public class MyClass
    {
        private readonly string _Name { get; set; }    
        private readonly IEnumerable<T> _Values { get; set; }    
        private IEnumerable<T> _MyProp { get; private set; }    
        public IEnumerable<T> MyProp
        {
            get
            {
                if(_MyProp == null)
                {
                    this.SetProp();
                }    
                return this._MyProp;
            }    
            private set; 
        }

        public MyClass(string Name, IEnumerable<T> Values)
        {
            this._Name = Name;
            this._Values = Values;
        }

        private void SetProp()
        {
              // Business logic using Name and Values
              this._MyProp = resultOfLogic;
        }

    }

链接的SO问题的已接受答案提到这不是一种线程安全的方法。有人可以建议为什么它不是,有没有办法以线程安全的方式做到这一点?

3 个答案:

答案 0 :(得分:4)

如果另一个线程正在运行,则该线程可以在测试和线程上SetProp()的调用之间调用SetProp()

我使用这样的代码,以使其更安全:

   // Dedicated object to lock for this property only
   private object myPropSync = new object();
   private T _myPropVal;
   public IEnumerable<T> MyProp
    {
        get
        {
            // Check if property is null
            if(_myPropVal== null)
            {
                // If null -> make sure you are the only one in the next section
                lock (myPropSync) {
                    // Re-test, because another thread can 
                    // set the property while waiting for the lock
                    if (_myPropVal== null) {
                         this.SetProp();
                    }
                }
            }    
            return this._myPropVal;
        }    
        private set {
          lock (_myPropSync) {
             _myPropVal = value;
          }
        }
    }

答案 1 :(得分:2)

  

有人可以提出建议吗

想象一下,有两个线程并行执行document.getElementById("rbtnZone").checked = true; document.getElementById("rbtnZone").checked = false; 。 然后就可以得到这个序列:

  • T1:get_MyProp - &gt;真
  • T2:_MyProp == null - &gt;真
  • T1:_MyProp == null - &gt; _MyProp已初始化
  • T2:this.SetProp(); - &gt; T2重写_MyProp值,由T1
  • 计算
  

如果有以线程安全方式执行此操作的方法

转换this.SetProp();而不是设置字段,并使用SetProp(默认情况下,初始化为thread-safe):

IEnumerable<T>

答案 2 :(得分:0)

我认为您发布的代码可能存在错误。片段

    public IEnumerable<T> MyProp
    {
        get
        {
            if(MyProp == null)
            { // ...

是无限递归的,会导致堆栈溢出(无资本化!)。

你的意思是最后一行使用_Values作为支持字段并测试null而不是MyProp?