我正在尝试从系统类(Lazy<T>
)重新实现功能,我发现了这个不寻常的代码。我明白了。尝试获取值的第一个线程执行计算。在发生这种情况时尝试的任何线程都会被锁定在门口,等待释放,然后去获取缓存的值。任何以后的调用都会注意到sentinel值,并且不再需要使用锁。
bool lockWasTaken = false;
var obj = Volatile.Read<object>(ref this._locker);
object returnValue = null;
try
{
if (obj != SENTINEL_VALUE)
{
Monitor.Enter(obj, ref lockWasTaken);
}
if (this.cachedValue != null) // always true after code has run once
{
returnValue = this.cachedValue;
}
else //only happens on the first thread to lock and enter
{
returnValue = SomeCalculations();
this.cachedValue = returnValue;
Volatile.Write<object>(ref this._locker, SENTINEL_VALUE);
}
return returnValue
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(obj);
}
}
但是,让我们说,在代码更改后,另一种方法将this._locker
重置为其原始值,然后进入锁定并重新计算缓存的值。虽然它这样做,但另一个线程碰巧正在拾取缓存的值,因此它位于锁定部分内,但没有锁定。怎么了?当带锁的线程同时并行时,它是否只是正常执行?
答案 0 :(得分:3)
虽然它这样做,但另一个线程恰好是拿起缓存的值,所以它在锁定的部分内,但是没有锁定。怎么了?当带锁的线程同时并行时,它是否只是正常执行?
是的,它只是正常执行。
话虽如此,这段代码似乎可以使用Lazy<T>
完全删除。 Lazy<T>
类提供了一种线程安全的方法来处理数据的延迟实例化,这似乎是此代码的目标。
基本上,整个代码可以替换为:
// Have a field like the following:
Lazy<object> cachedValue = new Lazy<object>(() => SomeCalculations());
// Code then becomes:
return cachedValue.Value;