如果不为null,则以线程安全的方式返回属性
本文关键字:安全 方式 返回 属性 线程 null 如果不 | 更新日期: 2023-09-27 18:27:09
我的问题实际上是这个SO问题的扩展,关于在返回属性之前测试属性为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问题的公认答案提到,这不是一种线程安全的方法。有人能告诉为什么不是,以及是否有方法以线程安全的方式做到这一点吗?
如果另一个线程正在运行,则该线程可以在测试和调用线程上的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;
}
}
}
有人能建议的原因吗
想象一下,有两个线程,它们并行执行get_MyProp
。然后就有可能得到这个序列:
- T1:
_MyProp == null
->true - T2:
_MyProp == null
->true - T1:
this.SetProp();
->_MyProp初始化 - T2:
this.SetProp();
->T2重写由T1计算的_MyProp值
如果有一种方法可以以线程安全的方式做到这一点,
将SetProp
转换为返回IEnumerable<T>
而不是设置字段,并使用Lazy<T>
(默认情况下,初始化将是线程安全的):
private IEnumerable<T> CalcProp()
{
// Business logic using Name and Values
return resultOfLogic;
}
public IEnumerable<T> MyProp
{
get { return _MyProp.Value; }
}
private readonly Lazy<IEnumerable<T>> _MyProp;
public MyClass(string Name, IEnumerable<T> Values)
{
this._Name = Name;
this._Values = Values;
this._MyProp = new Lazy<IEnumerable<T>>(CalcProp);
}
我认为您发布的代码中可能有错误。碎片
public IEnumerable<T> MyProp
{
get
{
if(MyProp == null)
{ // ...
是无限递归的,会导致堆栈溢出(未大写!)。
你是指最后一行使用_Values作为支持字段并测试其为null而不是MyProp吗?