再次仔细检查锁定和C#
|
最近,我一直在重构一些C#代码,并且发现了一些经过仔细检查的锁定实践。当时我还不知道这是一个坏习惯,我真的想摆脱它。
问题是我有一个应该延迟初始化的类,并且经常被许多线程访问。我也不想将初始化转移到静态初始化器,因为我计划使用弱引用来防止初始化的对象在内存中停留太长时间。但是,如果需要,我想“恢复”该对象,以确保以线程安全的方式进行。
我想知道是否在C#中使用ReaderWriterLockSlim并在第一次检查之前输入UpgradeableReadLock,然后在必要时输入用于初始化的写锁是否可以接受。这是我要记住的:
public class LazyInitialized
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private volatile WeakReference _valueReference = new WeakReference(null);
public MyType Value
{
get
{
MyType value = _valueReference.Target as MyType;
_lock.EnterUpgradeableReadLock();
try
{
if (!_valueReference.IsAlive) // needs initializing
{
_lock.EnterWriteLock();
try
{
if (!_valueReference.IsAlive) // check again
{
// prevent reading the old weak reference
Thread.MemoryBarrier();
_valueReference = new WeakReference(value = InitializeMyType());
}
}
finally
{
_lock.ExitWriteLock();
}
}
}
finally
{
_lock.ExitUpgradeableReadLock();
}
return value;
}
}
private MyType InitializeMyType()
{
// code not shown
}
}
我的观点是,没有其他线程应尝试再次初始化该项目,而一旦值初始化,许多线程应同时读取。如果获得了写锁,则可升级的读锁应阻止所有读取器,因此,在初始化对象时,其行为类似于在可升级的读锁开始处使用lock语句。初始化之后,可升级读锁将允许多个线程,因此不会出现等待每个线程的性能问题。
我在这里还读到一篇文章,说volatile导致在读取之前和写入之后自动插入内存屏障,因此我假设在读取和写入之间只有一个手动定义的屏障足以确保正确读取_valueReference对象。感谢您使用此方法的建议和批评。
没有找到相关结果
已邀请:
2 个回复
砷竣阿
翱抹村